What is Dark mode?

Dark mode: Dark mode is a color scheme that renders light text on dark surfaces, chosen by the user or taken from the operating system's preference.

Dark mode replaces a light interface with one built on dark surfaces and light text. Operating systems expose the user's choice, and browsers pass it to CSS through the prefers-color-scheme media feature. Most apps honor that preference by default and add a manual toggle with three options: light, dark and system. Done well, dark mode is not an inversion of the light theme. It is a second set of carefully chosen values for the same roles.

How it works

There are two common strategies. The media query strategy follows the OS automatically. The class strategy puts a class such as dark on <html> so the user can override the system, which is what apps with a toggle use. In Tailwind CSS v4 you point the dark: variant at the class and redefine tokens under it:

css
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));

:root {
  --bg: oklch(0.985 0.002 264);
  --fg: oklch(0.185 0.012 268);
  color-scheme: light;
}
.dark {
  --bg: oklch(0.145 0.004 270);
  --fg: oklch(0.965 0.003 270);
  color-scheme: dark;
}

The color-scheme property tells the browser to render its own UI, such as scrollbars, form controls and the default canvas, in the matching scheme.

Design guidelines

  • Avoid pure black. Near-black surfaces soften the glare of white text and leave room for depth below the page color.
  • Lightness shows elevation. Shadows barely read on dark backgrounds, so raised surfaces get slightly lighter instead.
  • Rebalance accents. A brand color tuned for white usually needs more lightness and a little less chroma on dark surfaces. OKLCH makes that adjustment predictable.
  • Recheck contrast. Every text and border pairing needs its own WCAG contrast check in both themes.
  • Theme images and charts. Screenshots, logos and chart palettes often need dark variants.

Common pitfalls

The classic bug is the flash: a server-rendered page arrives light, then turns dark once JavaScript reads the saved preference. It is a form of FOUC. The fix is a tiny blocking script in <head> that sets the class before the first paint, plus suppressHydrationWarning on <html> so React tolerates the changed attribute during hydration. Dark mode in Next.js without the flash walks through the full setup, including the system option and theme-color.

How MiniDev UI handles it

Dark mode in MiniDev UI redefines semantic tokens under .dark; components carry no dark: overrides for their core colors. Shadows, highlights and materials are retuned per theme too. ThemePicker is a three-way light, dark and system control that toggles the class and reports changes, so you can wire it to your own persistence.

Theme PickeruiLight, dark and system theme picker as a segmented radiogroup that toggles the dark class on the root element for Tailwind dark mode and reports it to onChange.npx shadcn@latest add ui.minidev.pro/r/theme-picker.json