Clawscale provider
ClawscaleProvider is the root provider of a Clawscale app. It renders Blueprint's BlueprintProvider for overlays, hotkeys and portals, and manages the theme, the accent and the light, dark and system color schemes. Wrap your app in it once.
Usage#
import { ClawscaleProvider, ThemeScript } from "@clawscale/react";In Next.js, render the provider in a client component and the theme script in <head>.
// app/providers.tsx
"use client";
import { ClawscaleProvider } from "@clawscale/react";
export function Providers({ children }: { children: React.ReactNode }) {
return <ClawscaleProvider>{children}</ClawscaleProvider>;
}// app/layout.tsx
import { ThemeScript } from "@clawscale/react";
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<ThemeScript />
</head>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}See Next.js for the full setup.
What it includes#
- OverlaysProvider: the stack of open dialogs, drawers and popovers.
- HotkeysProvider: the hotkeys registered with useHotkeys, and the hotkeys dialog.
- PortalProvider: where portals render.
- The theme context that useTheme reads.
Themes#
The provider applies a theme: default unless you pass defaultTheme, or a theme someone picked with setTheme. A theme other than the default needs its stylesheet from @clawscale/react/themes/.
import { HTMLSelect, useTheme } from "@clawscale/react";
import { themes } from "@clawscale/tokens";
const options = Object.values(themes).map(({ name, label }) => ({ label, value: name }));
export default function ClawscaleProviderThemeSwitcher() {
const { theme, setTheme } = useTheme();
return (
<HTMLSelect
aria-label="Theme"
options={options}
value={theme}
onChange={(event) => setTheme(event.currentTarget.value)}
/>
);
}Accents#
An accent sets the primary color: buttons, links, focus rings, selection and selected rows. Each theme lists its accents, its own first. The provider applies the theme's own until someone calls setAccent, or you pass defaultAccent. A saved accent that the active theme lacks falls back to the theme's own. See Themes.
Color schemes#
The provider supports three color scheme preferences: light, dark and system. system follows the operating system through prefers-color-scheme and updates when it changes.
import { type ColorSchemePreference, SegmentedControl, useTheme } from "@clawscale/react";
export default function ClawscaleProviderColorSchemeSwitcher() {
const { colorScheme, setColorScheme } = useTheme();
return (
<SegmentedControl
aria-label="Color scheme"
options={[
{ label: "Light", value: "light", icon: "flash" },
{ label: "Dark", value: "dark", icon: "moon" },
{ label: "System", value: "system", icon: "desktop" },
]}
value={colorScheme}
onValueChange={(value) => setColorScheme(value as ColorSchemePreference)}
/>
);
}Saved choices#
- The theme is saved in
localStorageunderclawscale-theme, the accent underclawscale-accentand the color scheme underclawscale-color-scheme. Change the keys withthemeStorageKey,accentStorageKeyandcolorSchemeStorageKey, or passnullto save nothing. defaultTheme,defaultAccentanddefaultColorSchemeapply until someone picks one. They default todefault, the theme's own accent andsystem.- All three go on
<html>: the theme asdata-cs-theme, a picked accent asdata-cs-accent, the color scheme as thebp6-darkclass,data-cs-color-schemeandcolor-scheme. Portals follow them. SetapplyToDocument={false}to skip this. - Open tabs stay in sync. A change in one tab applies to the others.
Theme script#
The provider reads the saved theme, accent and color scheme after hydration. On its own, the page would first paint with the defaults, then switch. ThemeScript prevents this flash: it runs before the first paint and applies them to <html>.
- Render it in
<head>. - Give it the same storage keys and defaults as the provider.
- Add
suppressHydrationWarningto<html>, because the script changes its attributes before React hydrates. - Pass
nonceif your Content Security Policy requires one.
Outside React, getThemeScript(options) returns the script as a string.
Controlled theme#
Pass theme and onThemeChange, accent and onAccentChange, or colorScheme and onColorSchemeChange, to own a setting, for example to sync it with account settings. The provider still saves it to localStorage, so ThemeScript applies it on the next visit.
<ClawscaleProvider colorScheme={colorScheme} onColorSchemeChange={saveColorScheme}>
{children}
</ClawscaleProvider>Upgrading from 0.1#
Before 0.2, "theme" meant light or dark. It now names the look, such as default, and light and dark are color schemes.
| Before 0.2 | Now |
|---|---|
theme, defaultTheme, onThemeChange with light, dark or system | colorScheme, defaultColorScheme, onColorSchemeChange |
resolvedTheme | resolvedColorScheme |
setTheme("dark") | setColorScheme("dark") |
storageKey | colorSchemeStorageKey |
data-cs-theme="dark" | data-cs-color-scheme="dark" |
The old names keep working until 1.0 and log a warning. A color scheme saved under clawscale-theme moves to clawscale-color-scheme on the next visit. Update CSS that selects [data-cs-theme="dark"] on <html>: the provider now writes the theme name there.
Blueprint options#
ClawscaleProvider passes the portal and hotkeys props on to BlueprintProvider. See where each one goes.
Props interface#
interface ClawscaleProviderProps extends Omit<BlueprintProviderProps, "children">@clawscale/react| Props | Description |
|---|---|
accent | stringControlled accent, for example "teal". Leave unset to let the provider manage it. |
accentStorageKey | string | null = "clawscale-accent"localStorage key for the accent. Pass null to skip saving it. |
applyToDocument | boolean = truePut the theme, accent and color scheme on the document element, so portals follow them. |
children | ReactNode |
colorScheme | ColorSchemePreferenceControlled color scheme preference. Leave unset to let the provider manage it. |
colorSchemeStorageKey | string | null = "clawscale-color-scheme"localStorage key for the color scheme. Pass null to skip saving it. |
defaultAccent | stringAccent used before anything is saved. Leave unset for the theme's own accent. |
defaultColorScheme | ColorSchemePreference = "system"Color scheme preference used before anything is saved. |
defaultTheme | ThemeName = "default"Theme used before anything is saved. |
focusRings | "keyboard" | "always" = "keyboard"When focus rings show. "keyboard" hides them after mouse clicks, "always" keeps Blueprint's behavior. |
hotkeysProviderDialogProps | Partial<Omit<HotkeysDialogProps, "hotkeys">>Optional props to customize the rendered hotkeys dialog. Inherited from HotkeysProviderProps |
hotkeysProviderRenderDialog | (state: HotkeysContextState, contextActions: { handleDialogClose: () => void; }) => React.JSX.ElementIf provided, this dialog render function will be used in place of the default implementation. Inherited from HotkeysProviderProps |
hotkeysProviderValue | HotkeysContextInstanceIf provided, we will use this context instance instead of generating our own. Inherited from HotkeysProviderProps |
onAccentChange | (accent: string | undefined) => voidCalled when setAccent runs. |
onColorSchemeChange | (colorScheme: ColorSchemePreference) => voidCalled when setColorScheme runs. |
onThemeChange | (theme: ThemeName) => voidCalled when setTheme runs. |
portalClassName | stringAdditional CSS classes to add to all Inherited from Portal elements in this React context.PortalContextOptions |
portalContainer | HTMLElementThe HTML element that all Inherited from Portal elements in this React context will be added as children toPortalContextOptions |
storageKeydeprecated | string | nullSince 0.2, use colorSchemeStorageKey. null turns off saving for both keys. |
theme | ThemeNameControlled theme, for example "default". Leave unset to let the provider manage it. |
themeStorageKey | string | null = "clawscale-theme"localStorage key for the theme. Pass null to skip saving it. |
interface ThemeScriptProps extends ThemeScriptOptions@clawscale/react| Props | Description |
|---|---|
accentStorageKey | string | null = "clawscale-accent"localStorage key for the accent. Must match the provider's Inherited from accentStorageKey.ThemeScriptOptions |
colorSchemeStorageKey | string | null = "clawscale-color-scheme"localStorage key for the color scheme. Must match the provider's Inherited from colorSchemeStorageKey.ThemeScriptOptions |
defaultAccent | stringAccent used when nothing is saved. Must match the provider's Inherited from defaultAccent. Leave unset for the theme's own accent.ThemeScriptOptions |
defaultColorScheme | ColorSchemePreference = "system"Color scheme used when nothing is saved. Must match the provider's Inherited from defaultColorScheme.ThemeScriptOptions |
defaultTheme | ThemeName = "default"Theme used when nothing is saved. Must match the provider's Inherited from defaultTheme.ThemeScriptOptions |
nonce | stringNonce for a strict Content Security Policy. |
storageKeydeprecated | string | nullSince 0.2, use Inherited from colorSchemeStorageKey.ThemeScriptOptions |
themeStorageKey | string | null = "clawscale-theme"localStorage key for the theme. Must match the provider's Inherited from themeStorageKey.ThemeScriptOptions |