Personal

RB Notes - A Floating Desktop Notes Widget I Built Because I Refused to Pay $8

A frameless, always-on-desktop notes widget for Windows 11, built out of frustration with the existing options.

April 4, 2026
ElectronReactTypeScriptWindows

View on GitHub

This article is continuously updated as the project grows. What's described here reflects v0.1.1-alpha.

Why this exists

I did a desktop overhaul. New wallpaper, new layout, the whole thing. As part of it I cleared a corner of the screen in the bottom right specifically for a sticky notes app I always had open. Nothing fancy, just somewhere to dump quick thoughts, tasks, and links without breaking flow.

The app I was using stopped working with the new setup. So I went looking for alternatives.

The first one I found was OpenStickies. It looked exactly like what I wanted, except it caps you at five notes on the free tier and wants an account and $8 to go beyond that. I get it, people deserve to be paid for their work. But I wanted a simple notes widget, not a subscription.

The second one was something someone posted on Reddit. Minimum $5 to access. Same story.

At that point I just started building.

What it is

RB Notes is a frameless floating notes window for Windows 11. It sits on your desktop, saves automatically, and stays out of the way. You can pin it on top of everything, or send it behind all your windows so it just lives on the desktop as a background layer.

It lives in the system tray so it's always one click away even when you've closed all the windows. Notes sync across multiple windows if you want more than one open at a time.

The project is on GitHub at ryanputraa/RB-Notes.

How it's built

The stack is Electron, React, and TypeScript, built with electron-vite and packaged via electron-builder with a Squirrel installer.

The window is completely frameless and transparent. Rounded corners come from the border-radius on the root div, not from the OS. The window chrome is a custom React component. Dragging is handled with -webkit-app-region: drag on the titlebar and no-drag on the buttons inside it.

The editor is a contenteditable div. I considered using an existing rich text library but the feature set I needed was small enough that rolling it myself made more sense. Bold, italic, strikethrough, headings, todo checkboxes, and links. Keyboard shortcuts wired via execCommand. Todo items are custom DOM elements with a checkbox and a contentEditable span inside a flex container.

Markdown-style shortcuts work as you type. Type **text** and it converts to bold on the closing **. Same for *italic*, triple backtick for a code block, and - at the start of a line for a bullet point. The implementation intercepts the input event, runs a regex against the text content before the cursor in the current text node, and does a targeted DOM replacement if it matches.

Theming is done with CSS custom properties injected into :root via a <style> tag updated whenever settings change. This means the background color, text color, accent, font size, and font family all respond instantly without a reload. Dark and light themes are separate color sets you can configure independently. Window opacity goes through Electron's win.setOpacity() via IPC.

The app hides from the taskbar and Alt+Tab in all modes, by design. It also registers itself in the Windows system tray on startup.

A few things that were annoying to get right

Module resolution in dev mode. Electron 41 on Windows has a quirk where require('electron') in the bundled main process resolves to the npm package (which returns a path string) instead of the built-in Electron API, because node_modules/electron/ shadows it during dev. The app only runs correctly from the built executable, not from npm run dev. Not ideal for iteration speed, but workable.

The frameless window drop shadow. Setting hasShadow: false and applying a box-shadow via CSS gives full control over the shadow style without the OS interfering. On Windows the transparent Electron window composites correctly as long as transparent: true is set on the BrowserWindow.

Squirrel installer naming. Squirrel derives the installer filename from the package.json name field, not productName, and it lowercases it. The workaround is a post-build rename in the npm script.

Tray icon rendering. Calling .resize() on a nativeImage loaded from a .ico file converts it to a raw bitmap that the Windows tray can't render correctly. Pass the nativeImage directly and let Windows pull the right resolution from the ICO's embedded size list.

Settings

There's a settings panel behind the gear icon in the titlebar. From there you can change the background color for dark and light themes separately, text color, accent color, font family (system, monospace, or serif), font size, window opacity, and whether to launch at startup. There's also an option to wipe all note data when the app is uninstalled, which hooks into the Squirrel uninstall lifecycle event.

Font size can also be changed with Ctrl+Scroll anywhere in the window, and there are inline +/- buttons in the toolbar next to the word count.

Data

Notes are saved to %AppData%\RB Notes\notes-data.json as JSON. Window position and size are saved separately in winstate.json so the window remembers where you left it. Everything auto-saves on a 700ms debounce as you type.

Next steps

A few things I want to add, roughly in priority order:

  • Search across notes: a quick search bar to find text across all your notes
  • Note pinning: pin specific notes to always show at the top of the dropdown
  • Resizable columns: side-by-side note view for when you have multiple windows open
  • Keyboard shortcut to show/hide: a global hotkey to bring RB Notes into focus from anywhere
  • More markdown shortcuts: ordered lists, blockquotes, inline code with single backtick
  • If you have any ideas, feel free to reach out