Modes

Ragnar ships three modes — light, dim, and dark — controlled entirely by the data-mode attribute. Mode swapping is a single attribute change with zero JavaScript on the critical path.

Overview

A mode is the second layer of Ragnar's token architecture. It decides what the --backgrounds-* and --foregrounds-* tokens resolve to, plus the per-palette --<palette>-main / -background / -tint / -foreground / -shade mappings. Themes consume those tokens to color components.

Lightdata-mode="light"
Dimdata-mode="dim"
Darkdata-mode="dark"

The three modes

Light

Cool monochrome — backgrounds run from mono-0 (pure white) through mono-400, foregrounds from mono-950 down through mono-400. The default for most users who haven't expressed a preference.

Dim

Warm low-contrast — backgrounds and foregrounds both come from the teak palette instead of mono. The result is a sepia / parchment feel that's easier on the eyes than full light mode without going all the way to dark. Per-palette aliases shift up one shade (e.g. --maitai-main: var(--color-maitai-600) instead of 500) to keep accent colors readable on the warmer backgrounds.

Dark

Inverted monochrome — backgrounds run from mono-800 down to mono-950 (with mono-700/600 for elevated surfaces), foregrounds from mono-0 (pure white) down through mono-400. Palette aliases invert their dark / light roles — --<palette>-background is now the darkest shade (950), and --<palette>-foreground is the lightest (50).

How it works

Mode-aware tokens are CSS custom properties scoped by attribute selector. There's no class-toggle, no .dark selector duplication, no JS necessary at render time. data-mode on any ancestor cascades through.

Setup

Set data-mode on the <html> element for a global default:

app/layout.tsx

With next-themes

Use next-themes with attribute="data-mode"so its switcher writes Ragnar's mode attribute directly:

System preference

Pass enableSystem to next-themes and it will watch the OS preference and apply light or dark automatically. Dim is opt-in — the OS only signals light or dark, not warm-low-contrast.

Scoped mode

Because data-mode works on any ancestor, you can scope a single section to a different mode without touching the rest of the page. Useful for a darkened hero inside an otherwise light layout, or a dim-mode reading view: