ColourSchemeToggle
The light and dark switch.
Overview
A site that offers both schemes: one toggle in the header or controls.
Switch
import { ColourSchemeToggle } from "@hackcove/ui";
<ColourSchemeToggle />
ColourSchemeToggle in the page header: it switches <html>, remembers the choice and shows the scheme you would switch to.import { applyColourScheme, Button, ButtonGroup } from "@hackcove/ui";
<ButtonGroup label="Colour scheme">
<Button variant="outline" size="sm" onClick={() => applyColourScheme("light")}>
Light
</Button>
<Button variant="outline" size="sm" onClick={() => applyColourScheme("dark")}>
Dark
</Button>
</ButtonGroup>Schemes
import { ColourSchemeToggle } from "@hackcove/ui";
<ColourSchemeToggle schemes={{ light: "paper", dark: "dark" }} />
schemes, so the toggle swaps both classes.import { ColourSchemeToggle } from "@hackcove/ui";
<ColourSchemeToggle />
schemes the toggle only adds and removes dark, so the light theme's own class is never put back.Usage
- Use one
ColourSchemeToggleper site. It switches<html>between light and dark and remembers the choice inlocalStorage. - Put
colourSchemeScriptinline in<head>, so the stored or system scheme is on<html>before first paint and a light visitor never sees a dark flash. It knows only thedarkclass. - A light theme with a class of its own (thrifty-paper's
paper) passesschemes={{ light: "paper", dark: "dark" }}; render the same class on<html>on the server withschemeClass. - An app that knows the scheme on the server (from a cookie) passes
initial, setsstore={false}and persists fromonChange. It then leaves the head script out. - Do not build a switch from your own buttons; the functions below are what the toggle itself calls.
Accessibility
- It is an
IconButtonnamedSwitch to dark themeorSwitch to light theme, so the name says the action, and the icon isaria-hidden. - The icon shown is the scheme you would switch to: the moon on a light page, the sun on a dark one. It follows the class on
<html>through CSS, so it is right on the first frame. applyColourSchemealso setscolor-schemeon<html>, so native controls and scrollbars follow.
API
ColourSchemeToggle
A sun/moon button that switches <html> between light and dark and remembers the choice. It shows the scheme you would switch to. Pair it with colourSchemeScript in <head>, unless you pass schemes or initial: the script knows only the dark class and the stored choice, so an app that sets the scheme itself leaves it out. An app whose light scheme has a class of its own passes schemes ({ light: "paper", dark: "dark" }); the toggle swaps those classes, and schemeClass gives the same one for the server to render on <html>. An app that knows the scheme on the server (from a cookie) passes it as initial, so the server markup, the hydrating client and the <html> class agree; persist a change from onChange. The icon follows the class on <html> through CSS, so even without initial a dark page shows the sun from the first frame; the button's name catches up once the client has hydrated. store={false} skips localStorage, for an app that keeps the choice in a server cookie and writes it from onChange. Every other button prop (id, data-*, aria-*) goes on the button.
initialThe scheme the server rendered. What the server and the hydrating client show; the real state follows right after. Default "light".
- Type
"light" | "dark"
onChange- Type
(scheme: ColourScheme) => void
schemesThe class each scheme puts on <html>. Default { light: "", dark: "dark" }.
- Type
ColourSchemeClasses- Default
{ light: "", dark: "dark" }
storeRemember the choice in localStorage. false leaves persisting to onChange. Default true.
- Type
boolean- Default
true
Functions
applyColourSchemePuts a scheme on<html>: its class, the other scheme's class taken off, andcolor-scheme.schemeClassThe class a scheme puts on<html>, for the server to render so the first paint is right; empty for the default light scheme.colourSchemeScriptA string of JavaScript to inline in<head>before first paint: applies the stored scheme, else the system one.readColourSchemeThe stored choice, else the system preference, with a fallback (default light) when neither is available, as on the server.storeColourSchemeRemembers a scheme inlocalStoragefor the next visit; a storage error is swallowed.