Clawscale

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#

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/.

Open dropdown
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 localStorage under clawscale-theme, the accent under clawscale-accent and the color scheme under clawscale-color-scheme. Change the keys with themeStorageKey, accentStorageKey and colorSchemeStorageKey, or pass null to save nothing.
  • defaultTheme, defaultAccent and defaultColorScheme apply until someone picks one. They default to default, the theme's own accent and system.
  • All three go on <html>: the theme as data-cs-theme, a picked accent as data-cs-accent, the color scheme as the bp6-dark class, data-cs-color-scheme and color-scheme. Portals follow them. Set applyToDocument={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 suppressHydrationWarning to <html>, because the script changes its attributes before React hydrates.
  • Pass nonce if 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.2Now
theme, defaultTheme, onThemeChange with light, dark or systemcolorScheme, defaultColorScheme, onColorSchemeChange
resolvedThemeresolvedColorScheme
setTheme("dark")setColorScheme("dark")
storageKeycolorSchemeStorageKey
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
PropsDescription
accent
string
Controlled 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 = true
Put the theme, accent and color scheme on the document element, so portals follow them.
children
ReactNode
colorScheme
ColorSchemePreference
Controlled 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
string
Accent 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.Element
If provided, this dialog render function will be used in place of the default implementation.
Inherited from HotkeysProviderProps
hotkeysProviderValue
HotkeysContextInstance
If provided, we will use this context instance instead of generating our own.
Inherited from HotkeysProviderProps
onAccentChange
(accent: string | undefined) => void
Called when setAccent runs.
onColorSchemeChange
(colorScheme: ColorSchemePreference) => void
Called when setColorScheme runs.
onThemeChange
(theme: ThemeName) => void
Called when setTheme runs.
portalClassName
string
Additional CSS classes to add to all Portal elements in this React context.
Inherited from PortalContextOptions
portalContainer
HTMLElement
The HTML element that all Portal elements in this React context will be added as children to
Inherited from PortalContextOptions
storageKeydeprecated
string | null
Since 0.2, use colorSchemeStorageKey. null turns off saving for both keys.
theme
ThemeName
Controlled 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
PropsDescription
accentStorageKey
string | null = "clawscale-accent"
localStorage key for the accent. Must match the provider's accentStorageKey.
Inherited from ThemeScriptOptions
colorSchemeStorageKey
string | null = "clawscale-color-scheme"
localStorage key for the color scheme. Must match the provider's colorSchemeStorageKey.
Inherited from ThemeScriptOptions
defaultAccent
string
Accent used when nothing is saved. Must match the provider's defaultAccent. Leave unset for the theme's own accent.
Inherited from ThemeScriptOptions
defaultColorScheme
ColorSchemePreference = "system"
Color scheme used when nothing is saved. Must match the provider's defaultColorScheme.
Inherited from ThemeScriptOptions
defaultTheme
ThemeName = "default"
Theme used when nothing is saved. Must match the provider's defaultTheme.
Inherited from ThemeScriptOptions
nonce
string
Nonce for a strict Content Security Policy.
storageKeydeprecated
string | null
Since 0.2, use colorSchemeStorageKey.
Inherited from ThemeScriptOptions
themeStorageKey
string | null = "clawscale-theme"
localStorage key for the theme. Must match the provider's themeStorageKey.
Inherited from ThemeScriptOptions