Skip to content

Getting started

Dark mode and motion

Light and dark ship together. One switch for motion; reduced motion always wins.

Dark mode#

Dark values apply under .dark or [data-theme="dark"] on any ancestor, usually <html>. Without React, set the class yourself. With React, ThemeProvider handles light, dark and system, remembers the choice, and follows the OS when set to system.

import { useTheme } from "junco";

const { theme, resolvedTheme, setTheme } = useTheme();
setTheme("system"); // "light" | "dark" | "system"

To stop server-rendered pages flashing the wrong theme, add themeScript() (from junco/server) as an inline script in <head>. It reads the saved choice before the first paint. Until it has read it, useTheme().isMounted is false, so toggles can avoid showing a wrong selected state.

The motion switch#

Set data-motion on <html> (or call setMotion). Every Junco duration is multiplied by --motion-scale, so one attribute turns all motion down.

Motion levels
Value--motion-scaleWhat happens
full1Everything animates at full distance and speed.
subtle0.6Shorter and smaller: less travel, quicker fades.
off0No movement. Spinners keep turning, slower, because they carry meaning.
reduced motion0The OS setting always wins, even over data-motion="full".
Rises in
With a stagger
Then settles

This spinner never stops, only slows down.

In your own CSS#

Use the duration utilities and they scale for free, or multiply by the variable yourself:

.panel {
  transition: transform calc(var(--duration-base) * var(--motion-scale)) var(--ease-enter);
}