Back

Dark mode for whiteboards is harder than it looks

On September 10, Bending Spoons agreed to buy Miro for about a tenth of what it was worth in 2022.

That’s a lot of people wondering what happens to a tool they use every day. So I went and read what they’d been asking for.

The top request on Miro’s idea board is dark mode. It was posted in May 2020. It’s now old enough to start first grade. It has 2,418 votes, 338 replies, and 90,167 views.

The very first post was polite. It thanked Miro and said dark mode would understandably be “no small task.”

It was right.

Miro's "Dark Mode / Night Mode" idea: open for six years, 2,418 upvotes, 338 replies, 90,167 views, with a pinned staff reply saying there are no immediate plans. 30% found it helpful.
The official answer. 30% found it helpful.

People keep asking anyway. New threads get opened and gently walked back to the original. Last fall, one arrived in all caps.

A Miro community question titled "WHY IS THERE STILL NO DARK MODE? don't you care what users are asking for?" noting users have asked for at least four years.
They said at least four years. They were being generous.

FigJam users have asked for the same thing since 2021.

CardBoard shipped dark mode this week. Here’s how we did it, and why it’s harder than it looks.

Most dark mode isn’t hard

Last fall a FigJam user called it “this simple feature.”

A FigJam forum post titled "Dark mode for figjam" calling it a simple feature, with zero replies.
Zero replies. The silence was, at least, very dark.

So which is it? No small task, or a simple feature?

Both. In most apps, every color has a job. Background. Text. Border. Button. Dark mode means writing a second set of colors for the same jobs. Flip a switch, swap the set, ship it.

That’s real work. But if that were all dark mode was on a whiteboard, it would have shipped years ago.

A whiteboard isn’t most apps

On a whiteboard, some of the colors aren’t yours. They belong to the person using it.

When someone makes a card yellow, yellow means something. Maybe it’s a risk. Maybe it’s a question for the client. If dark mode turns that yellow into mustard, you just changed what they meant.

So a whiteboard has three kinds of color, not one.

There’s the app: toolbars, menus, drawers. Those are ours, and they can go dark.

There’s the board: the cards and the background they sit on. Those belong to the user. They don’t change when the theme changes.

And there’s the stuff in between: selection rings, divider lines, the dashed outline around a suggested card. The app draws these, but it draws them on top of the user’s colors. They have to stay readable on any background the user picks.

The three kinds of color on a whiteboard, and which ones the theme is allowed to touch The same board drawn six times, in three columns of two. Each row is one setup: a light theme on a light board, and a dark theme on a dark board. Column one highlights the app chrome, a toolbar and a drawer, which is light in the top row and near-black in the bottom row. Column two highlights three cards, yellow, blue and pink, which are the identical colors in both rows. Column three highlights the marks the app draws on top of the board: a divider line, a blue selection ring with corner handles, and a dashed outline around a proposed card. These are recolored between rows so they stay legible on whichever board the user picked. 1 The app Toolbars, menus, drawers. Ours, so they flip with the theme. 2 The board Yours. The cards keep their exact colors in either theme. 3 The marks between Ours, drawn on your colors. Recolored to stay readable. LIGHT THEME light board DARK THEME dark board
Only the left column is ours to recolor. The middle column is the one that has to survive.

That third group is where it gets hard. It’s also where the workarounds fall apart.

The most popular workaround, on Miro and FigJam alike, is to draw a black rectangle the size of the board, send it to the back, and lock it. This is, technically, dark mode. It is also, technically, a rectangle.

The next step up is a browser extension like Dark Reader. An extension can’t tell the three kinds of color apart, so it darkens everything. One Miro user, whose company requires Miro, runs it every day. When they edit text, it goes so faint they have to click away to see what they typed, then click back in to keep going. The board itself stays bright white.

A Miro community post describing Dark Reader making edit-mode text low contrast and the background staying bright white. The topic is closed for replies.
Closed for replies. The migraines were not.

I can’t tell you why Miro and FigJam haven’t shipped it. I can show you what was hard for us.

The map

We plan our work in CardBoard, so dark mode got a story map.

CardBoard's "Introduce Dark Mode" story map, shown in dark mode: six activities across the top, cards grouped into Release 1 Foundation, Release 2 Dark chrome beta, Release 3 GA polish, and a final Promote dark mode slice holding one card.
24 cards say DONE. The last one is this post.

The top row is the path: audit every screen, name the colors, move the code over, build the switch, design the dark theme, ship. Under it, the work is cut into three releases.

First, change everything underneath and nothing on screen. Then turn dark mode on for our own team only. Then hunt down the edge cases and give it to everyone.

Start to finish, it took about three days. I directed the work through Claude.

We had one unfair advantage. Nobody had to approve it but me.

Four boards

The first thing dark mode broke was our board backgrounds.

CardBoard used to offer a row of pastel backgrounds. Most boards never used them, and none of them had a dark version. Put a pastel board inside dark menus and it glowed.

So we cut them. Now there are four: Light, the whiteboard; Medium, a quiet gray; Dark, the blackboard; and Chalkboard.

The background is your choice, not the theme’s. Pick Dark, and everyone you share the board with sees Dark, whatever theme they use.

Then Dark looked wrong. The first version was a shade lighter than the toolbar sitting on it, so the toolbar looked like it was slowly sinking into a tar pit. On a real desk, the thing on top catches more light. So we pushed Dark down until it was the darkest layer, and let the toolbars and drawers sit above it.

The green took the longest. Most greens look like Minecraft. We wanted a chalkboard, not a creeper. The one we kept has barely any color in it. You notice it as warmth more than as green.

Five candidate chalkboard greens, from near-neutral to Minecraft Five board canvases side by side, each carrying the same three cards in yellow, blue and pink and a white chalk label, so each green is judged the way it is actually used. All five sit at the same lightness and the same hue; only the chroma changes, rising from 0.005 on the left to 0.090 on the right. Left to right: near-neutral at hex 303331, whose hue is invisible on screen; the shipped Chalkboard at 2D342F, outlined, which reads as warmth rather than as green; Sage at 26372B, where people start naming the color instead of the surface; Blackboard at 183A25, the literal schoolroom green, which competes with the cards; and Creeper at 003F1C, which looks like Minecraft. Release 1 A Near-neutral #303331 C 0.005 Hue is there on paper, invisible on screen. Release 1 SHIPPED ✓ Chalkboard #2D342F C 0.013 Reads as warmth, not as green. A temperature. Release 1 B Sage #26372B C 0.030 People start naming the color, not the surface. Release 1 C Blackboard #183A25 C 0.055 The literal schoolroom green. Competes with cards. Release 1 D Creeper #003F1C C 0.090 Minecraft. Clipped out of sRGB on the way down.
Same lightness, same hue. Only the chroma moves. White chalk clears 12:1 on all five, so contrast was never what decided it.

Last, the dividers. They were one flat gray, and a gray line on the Medium board nearly disappeared. Now each line takes its color from the board it’s drawn on.

The same divider on four boards, before and after it took its color from the canvas Eight panels, four boards across and two rows down. The top row draws every divider in one flat mid-gray, hex 9698AC: it is legible on Light, Dark and Chalkboard, but on the Medium board it is so close to the canvas that it nearly disappears, at about one and a half to one. The bottom row derives each line from its own board instead, as the canvas tint at thirty-two percent, so the rule is darker than a light canvas and lighter than a dark one, and the divider's name sits in a faint chip in the canvas ink. Line colors left to right are A6A6A9 on Light, A2A6AD on Medium, 606062 on Dark and 707572 on Chalkboard. Light Release 1 #9698AC Release 1 #A6A6A9 Medium Release 1 #9698AC Release 1 #A2A6AD Dark Release 1 #9698AC Release 1 #606062 Chalkboard Release 1 #9698AC Release 1 #707572 FLAT GRAY #9698AC PER BOARD rgba(tint, .32)
One gray could not be right on four boards. It sat at about 1.5:1 on Medium, near enough to the canvas to vanish, while shouting at 6.4:1 on Dark. Each line now takes the opposite pole from the board it is drawn on, so it stays a quiet rule everywhere instead of the right answer in one place.

Making the switch boring

Every color in CardBoard used to be named for how it looked. Gray 100. Cobalt 600.

You can’t make “gray 100” dark. The name would lie.

So we renamed the colors by their job instead: surface, primary text, subtle border. Then we moved 1,357 color references in the code onto the new names.

Once every color had a job, the dark theme was just a second answer to the same questions. It came out to about 60 lines.

This part went fast because the hard half was already done. Last month we went looking for our card palette, so an agent could name a color and mean it. We found it living in five places at once. Cutting that to one is its own story. By the time dark mode came around, the habit was set and most of the plumbing was in.

Hunting corners

Dark mode breaks in the corners, so we went looking for corners.

The drawer that connects a board to Jira or Azure DevOps. The suggested cards Claude proposes on your board. The little marks that show a collapsed section. The Azure DevOps sign-in page, where our own heading went invisible.

We checked each one on all four boards. Every dark text color passes the WCAG AA contrast standard. And the page never flashes white when it loads, because the theme is set on the server before anything paints.

The last card

The last row on the map is called “Promote dark mode.” It has one card in it.

You’re reading it.

Try it

New to CardBoard? Right after you enter your name, we’ll ask: light or dark? Your first board will match.

CardBoard's onboarding theme step: a card headed "How should CardBoard look?" with the subtitle "Pick a theme. You can change it anytime in settings." Two board previews sit side by side, Light selected and Dark beside it, and both show the same four colored cards. Below them, a Continue button and a "Skip for now" link.
The same four cards in both previews. That's the whole argument, made before you've seen a board.

Already using CardBoard? Go to Preferences → Display & appearance.

Each board also has its own background, Light, Medium, Dark, or Chalkboard, in board settings.

Start free →