Skip to content
Facade UI
Colour mode
GitHub (opens in a new tab)

Theming

Facade UI has two token families, and knowing which one you are touching is most of the story.

shadcn names

Colour and radius use shadcn's own names — --background, --primary, --muted, --border, --ring, --radius. Sections reference nothing else, which is why a section dropped into an existing shadcn project inherits that project's theme with no edits at all.

One deliberate difference: Facade's default --ring is darker than shadcn's. The stock value sits at roughly 2.2:1 against a white background, below the 3:1 that WCAG 2.2 requires for a non-text indicator. If you keep your own ring colour, check it.

Facade names

Everything marketing-specific is prefixed --facade- so it can never collide with a token shadcn might add later.

Facade-prefixed design tokens
TokenPurposeNotes
--facade-text-display-sm/md/lg/xlFluid display scaleclamp() based, so headlines need no breakpoint juggling
--facade-section-y-sm/–/lgVertical rhythmConsumed by Section's spacing prop
--facade-container-maxMeasureDrives Container size="lg" and max-w-facade
--facade-container-gutterHorizontal paddingThe gutter Container applies below sm
--facade-duration-fast/base/slowMotion durationsMirrored in lib/motion.ts and checked by a test
--facade-ease-out/in-out/springMotion easingsExposed as ease-facade-* utilities
--facade-motion-distanceTravel distanceHow far FadeIn and Reveal translate

Presets

Three presets ship with the registry. Neutral is the default and needs no attribute; warm and vivid are applied with data-facade-theme on <html> or on any subtree. Light and dark are an independent axis, set by the dark class — try both switches in the header.

Applying a preset
<html data-facade-theme="warm">        <!-- warm, light -->
<html class="dark" data-facade-theme="warm">  <!-- warm, dark -->

Making your own

Override the shadcn-named tokens in one block and every section re-themes. Nothing else needs to change.

app/globals.css
[data-facade-theme="brand"] {
  --background: oklch(1 0 0);
  --foreground: oklch(0.17 0.02 264);
  --primary: oklch(0.48 0.18 264);
  --primary-foreground: oklch(0.99 0 0);
  --muted: oklch(0.96 0.01 264);
  --muted-foreground: oklch(0.47 0.03 264);
  --border: oklch(0.91 0.01 264);
  --ring: oklch(0.48 0.18 264);
}

Check the result rather than trusting it. Every preset in this repo is verified by scripts/check-contrast.ts, which resolves each theme scope from the real CSS and fails the build if a text pair drops below 4.5:1 or the focus ring below 3:1. Point it at your own preset before you ship it.