Theming
Applying a theme
Load a theme, set its identity class, and choose colour modes.
A themed document needs the shared Luke UI stylesheet, one theme stylesheet, and that theme's
identity class on <html>. Theming is static CSS, so it needs no provider. Read
Installation for the imports, and for where to set the
classes in a single-page app or a framework that renders the document.
The identity class selects the theme's tokens. The shared stylesheet paints <body> with the
theme's base surface, text colour, and body font for every theme.
Use one identity class
Set exactly one identity class, on <html>. An identity class on any other element does nothing.
Two identity classes on <html> are not supported: the themes' rules compete, and stylesheet order
decides which values win. To switch themes at runtime, replace the class rather than adding a second
one.
Choose a colour mode
Without a colour mode, the document follows the system preference, and changes with it live. Set
data-color-mode="light" or data-color-mode="dark" on <html> to fix the mode for the whole
document, as in <html class="luke-ui-theme-tactile" data-color-mode="dark">.
The theme sets the native color-scheme property for each mode. Browser controls and scrollbars
then match the Luke UI content.
System mode exists only at the document level, and it means no attribute. When a preference control
offers "System", remove data-color-mode from <html>. Do not resolve the preference to light or
dark yourself, because the attribute would then stop following a later system change. Only
lowercase light and dark are valid values.
Set the mode before first paint
Put the identity class, and any mode you know in advance, in the initial HTML. When the mode comes
from a preference stored in the browser, set it with an inline script in <head>, before the page
paints. The script sets data-color-mode only for an explicit choice.
import { themeClassName } from '@luke-ui/theme-tactile';
import type { PropsWithChildren } from 'react';
// Runs before first paint. It sets an explicit mode only. Without one, the theme follows the
// system preference, so `system` needs no attribute.
const colorModeScript = `
try {
const mode = localStorage.getItem('color-mode');
if (mode === 'light' || mode === 'dark') document.documentElement.dataset.colorMode = mode;
} catch {}
`;
export function RootLayout({ children }: PropsWithChildren) {
return (
// The script changes `<html>` before React hydrates it.
<html className={themeClassName} lang="en" suppressHydrationWarning>
<head>
<script dangerouslySetInnerHTML={{ __html: colorModeScript }} />
</head>
<body>{children}</body>
</html>
);
}In a single-page app, put the same script in a <script> element in the <head> of index.html.
In a framework that renders <html>, set suppressHydrationWarning on it, because the script
changes <html> before React hydrates it.