22 CSS Dark Mode UI

A CSS dark-mode UI is a surface whose theme system, tokens, and toggle contract are production primitives — not a colour swap. These 22 hand-coded patterns cover prefers-color-scheme, [data-theme], color-mix(), light-dark(), WCAG 2.4.13 focus rings, a System / Light / Dark switcher, and full UI surfaces — sidebars, dashboards, modals, code editors, OLED cards, layered slate. Every demo is scoped under .dmu-NN, uses pure-CSS :has(:checked) toggles that flip on any OS, guards motion behind prefers-reduced-motion, and drops into React, Vue, Svelte, or Astro without framework lock-in.

21 pure CSS1 light JSPublished 10 new designs · Updated on

Related5 CSS Variable Dark Mode Systems10 CSS Dark Mode Toggles12 CSS Neon Designs

Dark Mode UI with prefers-color-scheme Root Strategy — preview
01 / 22Pure CSSNEW

Dark Mode UI with prefers-color-scheme Root Strategy

The baseline pattern every other dark-mode technique builds on: declare your token block once on the component root, then let one media query re-declare the same token names for dark. No toggle, no attribute, no script — the UI simply obeys the operating system. Three panels render identical markup: a forced-light reference, a forced-dark reference, and one live panel that follows your current OS preference right now.

Published

Dark Mode UI with data-theme Attribute Override — preview
02 / 22Pure CSSNEW

Dark Mode UI with data-theme Attribute Override

The layer you add when a visitor needs to disagree with their operating system. A [data-theme] attribute wins over the media query, and a pure-CSS toggle — a visually hidden <input type="checkbox"> read by :has(:checked) — wins over both. Includes the nested-media flip-back rule, the one line that stops the toggle from silently doing nothing for visitors whose OS already matches your default.

Published

Dark Mode Token System with color-mix and CSS Custom Properties — preview
03 / 22Pure CSSNEW

Dark Mode Token System with color-mix and CSS Custom Properties

The architecture that stops a dark theme from becoming forty hand-picked hex codes. Declare a primitive ramp once (--gray-0--gray-12, --accent-500), then derive every semantic token — surface, elevated surface, hairline, ink, muted ink, accent wash — with color-mix(in oklab, …). Two cards sit on opposite surfaces using the identical token names to prove the derivation adapts instead of inverting.

Published

Dark Mode UI with light-dark CSS Function — preview
04 / 22Pure CSSNEW

Dark Mode UI with light-dark CSS Function

The modern way to write a theme: no media query at all. Set color-scheme: light dark and declare every token once as light-dark(<light>, <dark>). The function resolves against the element's effective colour scheme at compute time, so changing color-scheme anywhere re-themes the whole subtree — which makes the toggle a single property change instead of a second token block.

Published

Adaptive Dark Mode Sidebar Navigation — preview
05 / 22Pure CSSNEW

Adaptive Dark Mode Sidebar Navigation

A production navigation rail — brand lockup, six sections with live counters, a settings row and an account footer — that stays legible under both themes because every surface, icon stroke and hairline is a token. The active item carries a filled surface and an accent edge, so its state never depends on colour alone. A three-way System / Light / Dark segmented control sits in the footer, pure CSS, no script.

Published

Dark Mode Dashboard Card Grid — preview
06 / 22Pure CSSNEW

Dark Mode Dashboard Card Grid

Six metric cards — MRR, signups, churn, active users, response time, uptime — with inline SVG sparklines, tabular-figure readouts and delta chips that pair a direction arrow with colour so status never rests on hue alone. Cards sit on a gradient between two surface tokens, which is what stops a dark dashboard from reading as one flat black rectangle. Theme toggle in the header, pure CSS.

Published

Dark Mode Modal Dialog with Backdrop — preview
07 / 22Pure CSSNEW

Dark Mode Modal Dialog with Backdrop

A modal surface that behaves like a real one without a line of script: a <details> disclosure supplies the open state, the <summary> doubles as the trigger and the dismiss control, and a fixed blurred backdrop sits between them. The sheet uses an elevated surface with an inner-glow hairline — the detail that separates a dark modal from a grey box — and animates in with @starting-style so the entrance costs nothing at runtime.

Published

Dark Mode Form with Focus Ring Contrast Audit — preview
08 / 22Pure CSSNEW

Dark Mode Form with Focus Ring Contrast Audit

A sign-in form where the focus indicator is the feature. Every interactive control — email, password, the reveal toggle, remember-me, both buttons and the recovery link — carries a 2px outline in a per-theme focus token: bright cyan on dark, deep violet on light, each measured at 3:1 or better against the surface it lands on. An annotation ribbon lists what was tuned and the contrast value it hit.

Published

Three State Theme Switcher (System / Light / Dark) — preview
09 / 22Pure CSSNEW

Three State Theme Switcher (System / Light / Dark)

The control users actually expect in 2027: three states, not two. System ships no override at all and lets prefers-color-scheme through; Light and Dark pin explicit token sets that win over the media query. Three radios, three labels, one sliding thumb, zero JavaScript — plus a live badge that reports what the OS is currently asking for, so the difference between "System" and "Dark" is visible rather than theoretical.

Published

Dark Mode Code Editor Surface with Syntax Layer — preview
10 / 22Pure CSSNEW

Dark Mode Code Editor Surface with Syntax Layer

An editor chrome — file tree, tab bar with a modified dot, gutter, code panel and status bar — where the syntax palette is a token set rather than a stylesheet per theme. Keyword, string, comment, function and number colours each own a variable, so the same highlighted markup reads correctly on a near-black editor surface or a paper-white one. Theme toggle sits bottom-right in the status bar, exactly where an editor puts it.

Published

OLED True Black Dark Mode Card — preview
11 / 22Pure CSS

OLED True Black Dark Mode Card

A product card built for OLED panels, where an unlit pixel is genuinely off: the page is #000 and every layer above it climbs a short surface ramp — #0a0a0a, #141414, #1c1c1c — instead of relying on shadows that a true-black substrate swallows. The result is deeper contrast, a measurably cheaper screen and an interface that looks like it was designed for the display rather than ported to it.

PublishedUpdated

Stealth Panel Minimalist Dark UI — preview
12 / 22Pure CSS

Stealth Panel Minimalist Dark UI

Maximum restraint: no borders, no shadows, no second accent — just surface separation, one hue and a lot of air. A settings panel with four preference rows covering the four control types you actually ship (checkbox, switch, radio pair, select), all styled from the same three tokens. Ghost buttons only. The theme toggle is one of the rows, so the control lives where a user would look for it.

PublishedUpdated

Inkwell Dark Mode Modal Dialog — preview
13 / 22Pure CSS

Inkwell Dark Mode Modal Dialog

An editorial take on the confirmation dialog: deep navy rather than neutral black, warm off-white ink rather than pure white, a serif display headline over a sans body. The palette is borrowed from newspaper dark modes, where warmth is what keeps long-form text comfortable — and it turns a destructive prompt into something that reads considered instead of alarming.

PublishedUpdated

Cyber Terminal Dark UI Panel — preview
14 / 22Pure CSS

Cyber Terminal Dark UI Panel

A terminal panel with prompt history, streamed output and a live input line — phosphor green on black, a 2% scanline overlay and a blinking block caret. The retro reference is deliberate, the contrast is not: the green is tuned to 11:1 against the substrate, dim output still clears 4.5:1, and the whole CRT layer disappears under prefers-reduced-motion.

PublishedUpdated

Mocha Warm Dark Mode Workstation — preview
15 / 22Pure CSS

Mocha Warm Dark Mode Workstation

Dark mode without the cold: a warm substrate of roasted browns, cream ink and a single burnt-orange accent, built as a focus writing surface with a title field, tag chips, word count and long-form copy. Warm dark themes measurably reduce the blue component of a bright screen at night, and they read as calm rather than clinical — Solarized's idea, rebuilt with 2027 typography and token discipline.

PublishedUpdated

Forest Dim Dark Mode Reading Surface — preview
16 / 22Pure CSS

Forest Dim Dark Mode Reading Surface

A reading surface tuned for length: a green-tinted near-black that scatters less than pure black, ink at a deliberate 12:1 rather than a harsh 18:1, a 68-character measure, a drop cap and generous leading. Headline, byline, hero image and four paragraphs of real prose — plus a font-size control and a theme switch, both pure CSS, because a reader that cannot be adjusted is not a reader.

PublishedUpdated

Slate Stack Layered Dark Mode Card — preview
17 / 22Pure CSS

Slate Stack Layered Dark Mode Card

The elevation reference for a dark design system: four surface tokens, each a measured step lighter than the last, stacked visually so the ramp is legible at a glance. A product tile holds three nested sub-cards, every level labelled with its token and step value — the artefact you paste into documentation when someone asks why the dark theme cannot just use shadows. Light-default with a dark override, mirroring the collection's toggle contract.

PublishedUpdated

Carbon Shelves Dark Mode File List — preview
18 / 22Pure CSS

Carbon Shelves Dark Mode File List

A file browser in the dark: folder tree, sortable column headers, alternating row tints derived with color-mix() rather than two hard-coded greys, and a selected row marked by an accent edge plus a checked box — never colour alone. Row density, hover feedback and focus rings are all tuned for the case that actually happens: forty rows, scanned quickly, on a dim screen.

PublishedUpdated

Onyx Ladder Dark Mode Timeline — preview
19 / 22Pure CSS

Onyx Ladder Dark Mode Timeline

A changelog you would actually read: five events alternating either side of a central rail, each in an elevated onyx card with a monospaced timestamp, a typed badge and a node that sits on the rail rather than beside it. The alternating layout is pure grid — no absolute positioning, no magic numbers — and it collapses to a single left-rail column on narrow screens without changing the markup.

PublishedUpdated

Phosphor Glow Dark Mode Card — preview
20 / 22Light JS

Phosphor Glow Dark Mode Card

A product-launch card with a genuinely emissive CTA: the glow is a wide, low-alpha box-shadow in the accent hue, layered under a tight inner highlight so the button looks lit rather than blurred. A live countdown ticks in tabular figures (fifteen lines of vanilla JS, no theming logic), and the ambient pulse behind the card stops dead under prefers-reduced-motion.

PublishedUpdated

Aurora Dim Dark Mode Landing Panel — preview
21 / 22Pure CSS

Aurora Dim Dark Mode Landing Panel

A launch hero with a real atmosphere: three offset radial gradients — green, violet, cyan — masked into the top of the panel so the aurora fades before it reaches the text. Headline, subhead, dual CTAs and a trust bar, sized to fill a viewport at any aspect ratio. The whole effect is background layers and one masked pseudo-element; nothing animates unless the visitor allows motion.

PublishedUpdated

Ember Pulse Dark Mode Alert Card — preview
22 / 22Pure CSS

Ember Pulse Dark Mode Alert Card

The card that has to be read: a billing failure notice on a dark surface with a warm ember accent, a slow pulse on the status node and a retry action that looks like the primary path. Severity is carried by an icon, a labelled chip and the copy itself — never by the colour alone — and the pulse stops entirely for visitors who ask for reduced motion.

PublishedUpdated

Build your own

Tweak the exact look in our visual generators — no signup, instant copy-paste.

FAQ

Frequently asked questions

How do I add dark mode to a CSS project without JavaScript?
Two pure-CSS entry points cover most cases. First, prefers-color-scheme — declare your tokens once on the root, then redeclare only the tokens inside @media (prefers-color-scheme: dark). The UI adapts to the operating system automatically with zero script. Second, [data-theme] attribute override — pair the media query with .root[data-theme="dark"] and .root[data-theme="light"] rules that WIN over the media query so a user preference can beat the OS. For an interactive toggle without any JavaScript, use a visually-hidden <input type="checkbox"> plus a <label> and read the state with :has(#your-id:checked) on the ancestor — the whole flow is pure CSS. Demos 01, 02, and 04 in this collection ship each pattern as a reference implementation. The gotcha every toggle build hits: on the visitor's OS-matching default, the :has(:checked) rule and the OS default land on the same colours, so the first click looks like it did nothing. Fix by adding a nested rule inside the @media block that restores the opposite base when :has(:checked) matches — the flip-back pattern makes the toggle work in both directions on any device.
Should dark mode use pure black (#000) or dark grey backgrounds?
Pure black is right for OLED and AMOLED screens — unlit pixels are genuinely off, so #000 costs less battery, gives infinite contrast and reads as intentional. Demo 11 uses this substrate with a short elevation ramp (#0a0a0a, #141414, #1c1c1c) for cards, rows and hover states, because a shadow on true black would be swallowed by the substrate — surface tokens do the depth work instead. For non-OLED displays, a very dark grey (roughly #0a0a0b to #111114) usually reads better: it softens the contrast with pure white text, and layering progressively lighter greys lets you show elevation without shadows. The right choice depends on your primary audience and device mix — dashboards used on desktop monitors typically pick dark grey; reading apps and streaming interfaces used on OLED phones and TVs pick true black. Every demo in this collection declares its ground colour as a --void or --bg token so you can swap between the two by editing one value.
How do color-mix() and light-dark() reduce dark-mode boilerplate?
The traditional pattern needs two full palettes — a light rule set and a dark rule set — that drift out of sync as you add tokens. color-mix(in oklab, base 90%, white 10%) collapses that to one: define primitive tokens once, then compose semantic tokens as mixes relative to currentColor or a base neutral, and the mix adapts automatically to the surface it lands on. Perceptual mixing in oklab keeps mid-mixes from going muddy the way sRGB does. The newer light-dark() CSS function goes further — set color-scheme: light dark on the root and every colour can be written as light-dark(#f4f4f5, #0a0a0a). The function reads the effective color-scheme at compute time, so a single [data-theme] swap on the root cascades through every declaration with zero media queries. Baseline widely available in Chromium since May 2024, Safari since March 2024, Firefox 120+ — production-safe for a codebase with a modern-browser floor. Demo 03 shows the color-mix primer, demo 04 shows light-dark(), and both wrap their bleeding-edge features in @supports gates with sRGB fallbacks declared first.
How do I meet WCAG 2.2 AA for a dark-mode focus ring?
SC 2.4.13 (Focus Appearance, AA in WCAG 2.2) requires focus indicators to be at least 2 CSS pixels thick and to reach 3:1 contrast against adjacent colours. Dark mode makes this harder because a saturated mid-tone ring that passes on white can drop to 1.8:1 against #0a0a0a. Two rules keep this reliable. First, calibrate a distinct --focus-ring token per theme rather than reusing the primary accent — bright cyan (#22d3ee) works on most dark surfaces because oklch(83% 0.13 200) sits high in lightness. Second, use outline: 2px solid var(--focus-ring); outline-offset: 2px; rather than a box-shadow ring — outlines respect outline-offset cleanly and never get clipped by overflow: hidden. Demo 08 is the reference implementation with an inline audit ribbon calling out the contrast values for every interactive control on the surface. Pair with SC 1.4.11 (Non-text Contrast, 3:1) for the borders around inputs and buttons in their idle state, and SC 1.4.3 (Contrast Minimum, 4.5:1) for body text against the dark background.
How should a three-state theme switcher (System / Light / Dark) work in pure CSS?
Three radio inputs sharing a name attribute, one label per state, and :has() selectors on the surface for the two explicit states — the System option is the DEFAULT and needs no override rule. The cascade goes: @media (prefers-color-scheme: dark) supplies the base when nothing is checked (System = follow OS); :has(#light:checked) overrides both media queries with explicit light tokens; :has(#dark:checked) overrides with explicit dark tokens. The subtle bug every implementation hits: inside @media (prefers-color-scheme: dark), add a :has(#light:checked) restore-light rule that WINS over the media query, and inside @media (prefers-color-scheme: light) add a :has(#dark:checked) restore-dark rule. Without those two nested rules, a visitor on the matching OS gets stuck on their default when they select the opposite. Demo 09 ships the reference wiring with an annotation ribbon labelling each selector and its role in the cascade. Bonus: pair the switcher with a JavaScript one-liner that syncs <meta name="theme-color"> so the browser chrome (address bar on mobile, title bar on macOS) tracks the theme.
How do I stop the flash of light content when the page loads in dark mode?
The flash happens when your HTML paints before your theme script runs — the browser shows the light default for one frame, the script sets [data-theme="dark"], and the whole page flips. Three complementary fixes. First, put a tiny synchronous script BEFORE the first paint that reads localStorage.getItem('theme') and stamps document.documentElement.setAttribute('data-theme', value) — put it in the <head> above every stylesheet link, keep it under 200 bytes, and skip any imports. Second, add <meta name="color-scheme" content="light dark"> in the head — the browser paints the default background-color and scrollbars in dark grey before your CSS loads, which eliminates the white flash even without JavaScript. Third, ensure your @media (prefers-color-scheme: dark) block sets color-scheme: dark on the root so native form controls, scrollbars and text-selection adopt dark styling immediately. Combining all three eliminates flash on cold loads, warm loads, view transitions and Safari's bfcache restores.
Which dark-mode design surfaces are worth building as reusable primitives?
Six carry most of the weight across dashboards, marketing and docs. First, a surface elevation ramp — --surface-0 through --surface-3 with 8-15 unit lightness steps in oklab — replaces box-shadow depth on true-black substrates and reads as physical layering. Second, a focus-ring token distinct from the primary accent, calibrated for 3:1 contrast against the dark surface (WCAG 2.4.13). Third, an --accent-glow token that pairs with --accent for emissive CTAs (demo 20's phosphor glow, demo 22's ember pulse) so glow intensity flips off in light mode. Fourth, a semantic status palette (--ok, --warn, --err) that reads correctly on both grounds — saturated mid-tones that pass on white often fail on #0a0a0a and need a lightness lift. Fifth, a --divider-strong and --divider-subtle pair so hairlines stay visible on the dark substrate without ringing every card. Sixth, tabular-nums typography via font-variant-numeric: tabular-nums for any numeric display — column-aligned figures read as data on dark surfaces where a lighter-weight body copy would blur. Demos 03, 06, 17, 18 and 19 each show one or more of these primitives in production context.
How portable are these dark-mode patterns across Tailwind, React, Vue, Svelte, and Astro?
Every demo is framework-agnostic vanilla CSS scoped under a single unique .dmu-NN root so it drops into any framework without leaking. Tailwind v3 users pair the demo with the darkMode: 'class' config so dark: variants respect the same [data-theme] attribute the demo listens to; Tailwind v4 uses @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)) in your CSS-first config. React and Next.js apps typically ship the theme decision as a Context provider that writes data-theme on document.documentElement — the demo CSS reads the attribute regardless of who sets it. Vue 3 users bind :data-theme="theme" on the layout root and useDark() from VueUse writes it. Svelte does it with bind:data-theme on the <svelte:element> root. Astro islands (client:visible) work with the pure-CSS demos as-is; for the interactive three-state switcher, hydrate a small island around demo 09's markup. SolidJS, Qwik, and Angular signals all map to the same [data-theme] attribute pattern. The light-dark() demo (04) is the most future-proof — with color-scheme: light dark on the root, a single attribute swap cascades through every colour declaration with zero framework glue.

Related collections

9 CSS 3D Designs preview

9 CSS 3D Designs

9 hand-coded CSS 3D scenes built with real transforms, perspective, and preserve-3d — iridescent flip cards, a midnight coverflow carousel, kinetic tilt pricing cards, a page-turn flipbook, a Bauhaus drag-cube navigator, a modular synth control panel, a luxury hover-flip product showcase, a 5×5 spinning cube matrix, and a 60-orb DNA double helix. No WebGL, no libraries.

22 CSS Brutalism preview

22 CSS Brutalism

22 hand-coded brutalist and neubrutalist CSS designs covering the full spectrum of the aesthetic — from the anti-design brutalism of 2014-2018 (raw system fonts, zero border radius, monochrome density, visible structure) through to the neubrutalism of 2021-present (bright pastel fills, thick black borders, hard offset shadows with zero blur, rounded blocks). The neubrutalist half ships SaaS pricing cards with sticker badges, a pastel admin dashboard, signup forms, rotated feature cards, an offset-shadow navbar, a playful button set, a native dialog modal, a testimonial wall, blog cards, chunky toggles, a landing hero, an image gallery, stats panels and a rounded footer. The brutalist half covers product grids, raw form controls, a monochrome data dashboard, a portfolio index, indie SaaS pricing, Windows 95 desktop chrome, editorial long-read and a streetwear catalog. Every design is scoped under a .brt-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

16 CSS Frosted Glass Effects preview

16 CSS Frosted Glass Effects

16 production CSS frosted glass effect designs with live demos and copy-paste code — a full-viewport login modal, dashboard overlay panel, sticky glassmorphism navbar with blur-on-scroll via IntersectionObserver, sidebar navigation menu, media-player footer overlay, animated login/signup form, split-panel contact form UI, profile info card, credit card payment UI, product display card, crypto finance dashboard, Apple-style weather widget, glass music player UI, translucent calendar widget, frosted glass modal popup, and a VisionOS-style floating app dock. Every demo uses backdrop-filter blur + saturation 180% on a colorful animated backdrop for real glassmorphism, with a @supports fallback so browsers without support stay readable. Scoped under .fg-NN, copy-paste ready.

Search CodeFronts

Loading…