Skip to content
Facade UI

Theme customiser

To open the customiser, select the palette button in the header. It works on any page. The whole site changes as you choose, so there is no separate preview.

Start with three choices:

  • Brand colour: any Tailwind colour, or your own hex code.
  • Neutral: the grey used for backgrounds, borders and text.
  • Corners: how round they are.

The brand colour and the neutral generate every colour for light and dark mode. The result always passes the contrast checks below.

Advanced shows every colour token as a hex code and as OKLCH values. When you edit tokens by hand, a colour pair can fail, so the customiser checks your theme as you type. It uses the same colour pairs and minimum ratios as scripts/check-contrast.ts, the script that tests this project.

Your theme is saved in your browser. It appears as one more preset, Custom, until you select Reset.

Contrast

The default theme, checked with the same colour pairs and minimum ratios as scripts/check-contrast.ts.

light

Contrast results for the light palette
PairRatioResult
Body text19.75:1 (min 4.5)Passes
Secondary text7.64:1 (min 4.5)Passes
Secondary text on muted backgrounds7.01:1 (min 4.5)Passes
Card text19.75:1 (min 4.5)Passes
Popover text19.75:1 (min 4.5)Passes
Primary button label5.50:1 (min 4.5)Passes
Secondary button label16.04:1 (min 4.5)Passes
Text on accent backgrounds6.41:1 (min 4.5)Passes
Destructive button label4.56:1 (min 4.5)Passes
Primary colour as a fill or icon3.59:1 (min 3)Passes
Focus ring3.59:1 (min 3)Passes
Focus ring on cards3.59:1 (min 3)Passes
Form field border3.07:1 (min 3)Passes
Form field border on cards3.07:1 (min 3)Passes

dark

Contrast results for the dark palette
PairRatioResult
Body text18.92:1 (min 4.5)Passes
Secondary text7.63:1 (min 4.5)Passes
Secondary text on muted backgrounds5.87:1 (min 4.5)Passes
Card text16.76:1 (min 4.5)Passes
Popover text14.56:1 (min 4.5)Passes
Primary button label6.83:1 (min 4.5)Passes
Secondary button label14.56:1 (min 4.5)Passes
Text on accent backgrounds9.20:1 (min 4.5)Passes
Destructive button label6.83:1 (min 4.5)Passes
Primary colour as a fill or icon6.83:1 (min 3)Passes
Focus ring6.83:1 (min 3)Passes
Focus ring on cards6.05:1 (min 3)Passes
Form field border4.11:1 (min 3)Passes
Form field border on cards3.64:1 (min 3)Passes

Export

Paste this CSS into your stylesheet, after the Facade tokens. Then set data-facade-theme="custom" on <html>.

app/globals.css
[data-facade-theme="custom"] {
  --background: oklch(1 0 0);
  --foreground: oklch(0.147 0.004 49.25);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.147 0.004 49.25);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.147 0.004 49.25);
  --primary: oklch(0.646 0.222 41.116);
  --primary-foreground: oklch(0.147 0.004 49.25);
  --secondary: oklch(0.97 0.001 106.424);
  --secondary-foreground: oklch(0.216 0.006 56.043);
  --muted: oklch(0.97 0.001 106.424);
  --muted-foreground: oklch(0.444 0.011 73.639);
  --accent: oklch(0.954 0.038 75.164);
  --accent-foreground: oklch(0.47 0.157 37.304);
  --destructive: oklch(0.577 0.245 27.325);
  --destructive-foreground: oklch(0.985 0.001 106.423);
  --border: oklch(0.923 0.003 48.717);
  --input: oklch(0.664 0.01 56.259);
  --ring: oklch(0.646 0.222 41.116);
}

.dark[data-facade-theme="custom"],
.dark [data-facade-theme="custom"],
[data-facade-theme="custom"] .dark {
  --background: oklch(0.147 0.004 49.25);
  --foreground: oklch(0.985 0.001 106.423);
  --card: oklch(0.216 0.006 56.043);
  --card-foreground: oklch(0.985 0.001 106.423);
  --popover: oklch(0.268 0.007 34.298);
  --popover-foreground: oklch(0.985 0.001 106.423);
  --primary: oklch(0.705 0.213 47.604);
  --primary-foreground: oklch(0.147 0.004 49.25);
  --secondary: oklch(0.268 0.007 34.298);
  --secondary-foreground: oklch(0.985 0.001 106.423);
  --muted: oklch(0.268 0.007 34.298);
  --muted-foreground: oklch(0.709 0.01 56.259);
  --accent: oklch(0.266 0.079 36.259);
  --accent-foreground: oklch(0.837 0.128 66.29);
  --destructive: oklch(0.704 0.191 22.216);
  --destructive-foreground: oklch(0.147 0.004 49.25);
  --border: oklch(1 0 0 / 12%);
  --input: oklch(0.553 0.013 58.071);
  --ring: oklch(0.705 0.213 47.604);
}