Clawscale

Theming

Clawscale's look comes from design tokens. Change a token and every component follows. To switch the whole look at once, pick a theme.

How it works#

The stylesheets use cascade layers. Rules in a later layer win, whatever their specificity.

@layer blueprint, clawscale.base, clawscale.themes;

@layer blueprint {
  /* normalize.css and Blueprint's CSS, unchanged */
}

@layer clawscale.base {
  /* 1. tokens: --cs-* variables for the default theme, light and dark */
  /* 2. bridge: Blueprint's --bp-* tokens point at --cs-* tokens */
  /* 3. overrides for what Blueprint hardcodes */
}

@layer clawscale.themes {
  /* each theme stylesheet: its tokens, then its own rules */
}

Your own CSS is not in a layer, so it beats all of them. No !important needed.

Color schemes#

Every theme has a light and a dark color scheme. ClawscaleProvider puts the bp6-dark class and data-cs-color-scheme on <html>. It supports light, dark and system, and saves the choice. Read or change it with useTheme.

const { colorScheme, resolvedColorScheme, setColorScheme } = useTheme();

Override tokens#

Each color, shadow and chart token has a light and a dark value side by side, such as --cs-color-primary-light and --cs-color-primary-dark. Set both, and every color scheme picks its value.

:root {
  --cs-color-primary-light: #0e7c6b;
  --cs-color-primary-dark: #0e7c6b;
  --cs-color-primary-text-light: #0b6b5c;
  --cs-color-primary-text-dark: #4fd1b8;
  --cs-radius-md: 4px;
}

You can also set the final token for the whole page, with its dark value under the dark attribute.

:root {
  --cs-color-primary-text: #0b6b5c;
}

[data-cs-color-scheme="dark"] {
  --cs-color-primary-text: #4fd1b8;
}

See Tokens for every variable.

Scope tokens#

data-cs-theme and data-cs-color-scheme work on any element. Each re-applies the tokens for its subtree, so token values set on the same element apply there. This card restates the current theme and sets a teal brand.

us-east-1
import { Button, ButtonGroup, Card, Switch, Tag, useTheme } from "@clawscale/react";
import type { CSSProperties } from "react";

// Light and dark values side by side. The card picks the pair for the color scheme around it.
const brand = {
  "--cs-color-primary-light": "#0E7C6B",
  "--cs-color-primary-dark": "#0E7C6B",
  "--cs-color-primary-hover-light": "#0B6B5C",
  "--cs-color-primary-hover-dark": "#0B6B5C",
  "--cs-color-primary-active-light": "#095A4D",
  "--cs-color-primary-active-dark": "#095A4D",
  "--cs-color-primary-on-light": "#FFFFFF",
  "--cs-color-primary-on-dark": "#FFFFFF",
  "--cs-color-primary-text-light": "#0B6B5C",
  "--cs-color-primary-text-dark": "#4FD1B8",
  "--cs-color-primary-subtle-light": "rgba(14, 124, 107, 0.12)",
  "--cs-color-primary-subtle-dark": "rgba(79, 209, 184, 0.16)",
  "--cs-color-focus-light": "#0E7C6B",
  "--cs-color-focus-dark": "#4FD1B8",
} as CSSProperties;

export default function BrandColor() {
  // Restating the current theme makes the card pick its tokens again, from the values above.
  const { theme } = useTheme();
  return (
    <Card data-cs-theme={theme} style={{ ...brand, display: "grid", gap: 12, width: 340 }}>
      <ButtonGroup>
        <Button intent="primary" text="Deploy" />
        <Button intent="primary" variant="outlined" text="Preview" />
      </ButtonGroup>
      <Switch defaultChecked label="Auto-scale workers" />
      <Tag minimal intent="primary">
        us-east-1
      </Tag>
    </Card>
  );
}

Fonts#

@clawscale/react/fonts.css loads Inter and JetBrains Mono, and IBM Plex for the Ledger theme. Browsers download only the fonts a page uses. To use your own, set --cs-font-sans and --cs-font-mono.

Labels and corners#

Two token groups describe a theme's voice and shape, so your own components can match it.

  • --cs-label-transform and --cs-label-tracking set short labels, such as card titles. A theme can set them in capitals.
  • --cs-corner-shape is round or bevel. Pair it with a radius token to cut corners where the browser supports it.
.queue-title {
  letter-spacing: var(--cs-label-tracking);
  text-transform: var(--cs-label-transform);
}

.queue-panel {
  border-radius: var(--cs-radius-lg);
  corner-shape: var(--cs-corner-shape);
}

ClawscaleClasses.LABEL applies the label tokens as a class.

Density#

Clawscale sets a 13px base size and tabular numbers in tables. Use size="small" on buttons and inputs, compact on HTMLTable, CardList and Callout for denser screens.

Your own cascade layers#

If your app declares cascade layers, list Clawscale's first so yours win:

@layer blueprint, clawscale, app;