Theming
Unprefixed shadcn names. Light is :root. html.dark / html.light override.
With no class, the sheet follows prefers-color-scheme (authors who never run the FOUC script).
Dark/Light FOUC and the theme toggle live on Dark/Light Modes.
Color
Chart
--chart-1 … --chart-5 are tokens only.
The chart on /components/chart uses them.
Font
Library CSS uses the system UI stack. Do not copy site.css (Ubuntu Sans is only this docs site). Put your family in front of the
fallbacks in your own CSS.
Aspect ratio
aspect-ratio is a CSS property, not a component.
Complete themes
A complete color theme is a Light sheet plus a Dark sheet of the
same unprefixed CSS variables this library already uses. Load your
overrides after alumna-shadcn.css. Do not rename
tokens. This is copy-paste CSS, not a theme builder.
This docs site’s FOUC script always adds a class
(html.light or html.dark). Put Light
tokens on :root. Pair them with Dark tokens on html.dark so a class switch works. html.light only needs color-scheme: light — Light colors already live on :root, matching the
library. The class and storage story is on Dark/Light Modes.
Authors who never run that script get the library’s “no class → OS”
path. Copy the same Dark tokens into @media (prefers-color-scheme: dark) targeting html:not(.light) so Dark still applies when html has no class.
Override these groups:
- Color:
--backgroundthrough--ring(canvas, card, popover, primary, secondary, muted, accent, destructive, border, input). - Sidebar chrome, if you want it:
--sidebarthrough--sidebar-ring. - Charts:
--chart-1…--chart-5. - Radius:
--radius(the--radius-sm…--radius-4xlcalcs follow).
The full name list is the named blocks at the top of src/static/css/alumna-shadcn.css: /* 1. Tokens — light */ (:root) and /* 2. Tokens — dark (html.dark, or OS when html is not .light) */ (html.dark, then the html:not(.light) media query). Copy the names; assign your own oklch() values. Do not paste that whole Vega sheet into the page or into
your app CSS. Spacing, type scale, and shadows can stay.
A shadcn / Tailwind theme is not a drop-in. Drop @import "tailwindcss", @theme, @layer, and .dark. Keep the unprefixed
color tokens. Skip --destructive-foreground (this
library tints from --destructive alone), font-family
tokens (system stack in the library CSS), and Tailwind shadow /
tracking utilities. Use html.dark, not a nested .dark * variant.
The samples below are scoped to this page’s .docs-preview (docs-only classes in site.css). They do not restyle the docs nav or top
bar. Toggle Light/Dark to see each pair.
Minimal Neutral
Achromatic near-Vega canvas, larger radius 1rem. Light on :root; Dark on html.dark and the OS media query. Dark inverts
primary to pale gray; the card is darker than the page;
sidebar primary stays a saturated blue.
/* Minimal Neutral — Light. Load after alumna-shadcn.css. */
:root {
color-scheme: light;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(0.995 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.87 0 0);
--secondary-foreground: oklch(0.145 0 0);
--muted: oklch(0.95 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.95 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.95 0 0);
--input: oklch(0.97 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.81 0.1 252);
--chart-2: oklch(0.62 0.19 260);
--chart-3: oklch(0.55 0.22 263);
--chart-4: oklch(0.49 0.22 264);
--chart-5: oklch(0.42 0.18 266);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--radius: 1rem;
}
html.light {
color-scheme: light;
}
/* Minimal Neutral — Dark. FOUC / toggle: html.dark */
html.dark {
color-scheme: dark;
--background: oklch(0.205 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.165 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.371 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.81 0.1 252);
--chart-2: oklch(0.62 0.19 260);
--chart-3: oklch(0.55 0.22 263);
--chart-4: oklch(0.49 0.22 264);
--chart-5: oklch(0.42 0.18 266);
--sidebar: oklch(0.269 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.275 0 0);
--sidebar-ring: oklch(0.439 0 0);
--control-fill: color-mix(in oklab, var(--input) 30%, transparent);
--invalid-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 40%, transparent);
}
/* Minimal Neutral — Dark when html has no class (OS follow) */
@media (prefers-color-scheme: dark) {
html:not(.light) {
color-scheme: dark;
--background: oklch(0.205 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.165 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.371 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.81 0.1 252);
--chart-2: oklch(0.62 0.19 260);
--chart-3: oklch(0.55 0.22 263);
--chart-4: oklch(0.49 0.22 264);
--chart-5: oklch(0.42 0.18 266);
--sidebar: oklch(0.269 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.275 0 0);
--sidebar-ring: oklch(0.439 0 0);
--control-fill: color-mix(in oklab, var(--input) 30%, transparent);
--invalid-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 40%, transparent);
}
}Professional
Saturated blue primary on a cool gray canvas, tighter radius
(0.375rem). Light on :root; Dark on html.dark and the OS media query.
/* Professional — Light. Load after alumna-shadcn.css. */
:root {
color-scheme: light;
--background: oklch(1 0 0);
--foreground: oklch(0.1371 0.036 258.5258);
--card: oklch(1 0 0);
--card-foreground: oklch(0.1371 0.036 258.5258);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.1371 0.036 258.5258);
--primary: oklch(0.546 0.2153 262.8719);
--primary-foreground: oklch(0.9838 0.0035 247.8583);
--secondary: oklch(0.9684 0.0068 247.8951);
--secondary-foreground: oklch(0.2079 0.0399 265.7275);
--muted: oklch(0.9684 0.0068 247.8951);
--muted-foreground: oklch(0.5547 0.0407 257.4404);
--accent: oklch(0.9684 0.0068 247.8951);
--accent-foreground: oklch(0.2079 0.0399 265.7275);
--destructive: oklch(0.6368 0.2078 25.3259);
--border: oklch(0.929 0.0126 255.5317);
--input: oklch(0.929 0.0126 255.5317);
--ring: oklch(0.546 0.2153 262.8719);
--chart-1: oklch(0.546 0.2153 262.8719);
--chart-2: oklch(0.7211 0.1415 253.1015);
--chart-3: oklch(0.6325 0.1843 258.636);
--chart-4: oklch(0.8117 0.097 249.0979);
--chart-5: oklch(0.8829 0.0573 251.9139);
--sidebar: oklch(0.9838 0.0035 247.8583);
--sidebar-foreground: oklch(0.2079 0.0399 265.7275);
--sidebar-primary: oklch(0.546 0.2153 262.8719);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.929 0.0126 255.5317);
--sidebar-accent-foreground: oklch(0.546 0.2153 262.8719);
--sidebar-border: oklch(0.929 0.0126 255.5317);
--sidebar-ring: oklch(0.546 0.2153 262.8719);
--radius: 0.375rem;
}
html.light {
color-scheme: light;
}
/* Professional — Dark. FOUC / toggle: html.dark */
html.dark {
color-scheme: dark;
--background: oklch(0.1371 0.036 258.5258);
--foreground: oklch(0.9838 0.0035 247.8583);
--card: oklch(0.1371 0.036 258.5258);
--card-foreground: oklch(0.9838 0.0035 247.8583);
--popover: oklch(0.1371 0.036 258.5258);
--popover-foreground: oklch(0.9838 0.0035 247.8583);
--primary: oklch(0.6232 0.1879 259.7964);
--primary-foreground: oklch(0.2079 0.0399 265.7275);
--secondary: oklch(0.28 0.0369 259.974);
--secondary-foreground: oklch(0.9838 0.0035 247.8583);
--muted: oklch(0.28 0.0369 259.974);
--muted-foreground: oklch(0.7107 0.0351 256.7877);
--accent: oklch(0.28 0.0369 259.974);
--accent-foreground: oklch(0.9838 0.0035 247.8583);
--destructive: oklch(0.704 0.191 25.3259);
--border: oklch(0.28 0.0369 259.974);
--input: oklch(0.28 0.0369 259.974);
--ring: oklch(0.4878 0.217 264.3876);
--chart-1: oklch(0.4878 0.217 264.3876);
--chart-2: oklch(0.5449 0.2154 262.7414);
--chart-3: oklch(0.6776 0.1481 238.1044);
--chart-4: oklch(0.3752 0.0394 256.8467);
--chart-5: oklch(0.4691 0.1926 264.5776);
--sidebar: oklch(0.1371 0.036 258.5258);
--sidebar-foreground: oklch(0.9838 0.0035 247.8583);
--sidebar-primary: oklch(0.6232 0.1879 259.7964);
--sidebar-primary-foreground: oklch(0.1371 0.036 258.5258);
--sidebar-accent: oklch(0.28 0.0369 259.974);
--sidebar-accent-foreground: oklch(0.9838 0.0035 247.8583);
--sidebar-border: oklch(0.28 0.0369 259.974);
--sidebar-ring: oklch(0.4878 0.217 264.3876);
--control-fill: color-mix(in oklab, var(--input) 30%, transparent);
--invalid-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 40%, transparent);
}
/* Professional — Dark when html has no class (OS follow) */
@media (prefers-color-scheme: dark) {
html:not(.light) {
color-scheme: dark;
--background: oklch(0.1371 0.036 258.5258);
--foreground: oklch(0.9838 0.0035 247.8583);
--card: oklch(0.1371 0.036 258.5258);
--card-foreground: oklch(0.9838 0.0035 247.8583);
--popover: oklch(0.1371 0.036 258.5258);
--popover-foreground: oklch(0.9838 0.0035 247.8583);
--primary: oklch(0.6232 0.1879 259.7964);
--primary-foreground: oklch(0.2079 0.0399 265.7275);
--secondary: oklch(0.28 0.0369 259.974);
--secondary-foreground: oklch(0.9838 0.0035 247.8583);
--muted: oklch(0.28 0.0369 259.974);
--muted-foreground: oklch(0.7107 0.0351 256.7877);
--accent: oklch(0.28 0.0369 259.974);
--accent-foreground: oklch(0.9838 0.0035 247.8583);
--destructive: oklch(0.704 0.191 25.3259);
--border: oklch(0.28 0.0369 259.974);
--input: oklch(0.28 0.0369 259.974);
--ring: oklch(0.4878 0.217 264.3876);
--chart-1: oklch(0.4878 0.217 264.3876);
--chart-2: oklch(0.5449 0.2154 262.7414);
--chart-3: oklch(0.6776 0.1481 238.1044);
--chart-4: oklch(0.3752 0.0394 256.8467);
--chart-5: oklch(0.4691 0.1926 264.5776);
--sidebar: oklch(0.1371 0.036 258.5258);
--sidebar-foreground: oklch(0.9838 0.0035 247.8583);
--sidebar-primary: oklch(0.6232 0.1879 259.7964);
--sidebar-primary-foreground: oklch(0.1371 0.036 258.5258);
--sidebar-accent: oklch(0.28 0.0369 259.974);
--sidebar-accent-foreground: oklch(0.9838 0.0035 247.8583);
--sidebar-border: oklch(0.28 0.0369 259.974);
--sidebar-ring: oklch(0.4878 0.217 264.3876);
--control-fill: color-mix(in oklab, var(--input) 30%, transparent);
--invalid-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 40%, transparent);
}
}Tiesen
Violet primary on near-white / black canvas, radius 0.5rem. Same Light + Dark pairing as Professional.
/* Tiesen — Light. Load after alumna-shadcn.css. */
:root {
color-scheme: light;
--background: oklch(0.9851 0 0);
--foreground: oklch(0 0 0);
--card: oklch(1 0 267.51);
--card-foreground: oklch(0.2103 0 267.51);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0 0 0);
--primary: oklch(0.5144 0.1605 267.44);
--primary-foreground: oklch(0.97 0.014 254.604);
--secondary: oklch(0.94 0 0);
--secondary-foreground: oklch(0.25 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.44 0 0);
--accent: oklch(0.9214 0.0248 257.65);
--accent-foreground: oklch(0.2571 0.1161 272.24);
--destructive: oklch(0.58 0.22 27);
--border: oklch(0.92 0 0);
--input: oklch(0.94 0 0);
--ring: oklch(0.5144 0.1605 267.44);
--chart-1: oklch(0.9214 0.0248 257.65);
--chart-2: oklch(0.7597 0.0804 267.01);
--chart-3: oklch(0.6083 0.1247 272.72);
--chart-4: oklch(0.5144 0.1605 267.44);
--chart-5: oklch(0.2571 0.1161 272.24);
--sidebar: oklch(1 0 267.51);
--sidebar-foreground: oklch(0 0 0);
--sidebar-primary: oklch(0.5144 0.1605 267.44);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604);
--sidebar-accent: oklch(0.9214 0.0248 257.65);
--sidebar-accent-foreground: oklch(0.2571 0.1161 272.24);
--sidebar-border: oklch(0.92 0 0);
--sidebar-ring: oklch(0.5144 0.1605 267.44);
--radius: 0.5rem;
}
html.light {
color-scheme: light;
}
/* Tiesen — Dark. FOUC / toggle: html.dark */
html.dark {
color-scheme: dark;
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--card: oklch(0.2103 0 267.51);
--card-foreground: oklch(0.9461 0 0);
--popover: oklch(0.2103 0 267.51);
--popover-foreground: oklch(1 0 0);
--primary: oklch(0.6144 0.1605 267.44);
--primary-foreground: oklch(0.97 0.014 254.604);
--secondary: oklch(0.25 0 0);
--secondary-foreground: oklch(0.94 0 0);
--muted: oklch(0.23 0 0);
--muted-foreground: oklch(0.72 0 0);
--accent: oklch(0.32 0 0);
--accent-foreground: oklch(0.9214 0.0248 257.65);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(0.26 0 0);
--input: oklch(0.32 0 0);
--ring: oklch(0.5144 0.1605 267.44);
--chart-1: oklch(0.9214 0.0248 257.65);
--chart-2: oklch(0.7597 0.0804 267.01);
--chart-3: oklch(0.6083 0.1247 272.72);
--chart-4: oklch(0.5144 0.1605 267.44);
--chart-5: oklch(0.2571 0.1161 272.24);
--sidebar: oklch(0 0 0);
--sidebar-foreground: oklch(1 0 0);
--sidebar-primary: oklch(0.6144 0.1605 267.44);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604);
--sidebar-accent: oklch(0.32 0 0);
--sidebar-accent-foreground: oklch(0.9214 0.0248 257.65);
--sidebar-border: oklch(0.26 0 0);
--sidebar-ring: oklch(0.5144 0.1605 267.44);
--control-fill: color-mix(in oklab, var(--input) 30%, transparent);
--invalid-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 40%, transparent);
}
/* Tiesen — Dark when html has no class (OS follow) */
@media (prefers-color-scheme: dark) {
html:not(.light) {
color-scheme: dark;
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--card: oklch(0.2103 0 267.51);
--card-foreground: oklch(0.9461 0 0);
--popover: oklch(0.2103 0 267.51);
--popover-foreground: oklch(1 0 0);
--primary: oklch(0.6144 0.1605 267.44);
--primary-foreground: oklch(0.97 0.014 254.604);
--secondary: oklch(0.25 0 0);
--secondary-foreground: oklch(0.94 0 0);
--muted: oklch(0.23 0 0);
--muted-foreground: oklch(0.72 0 0);
--accent: oklch(0.32 0 0);
--accent-foreground: oklch(0.9214 0.0248 257.65);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(0.26 0 0);
--input: oklch(0.32 0 0);
--ring: oklch(0.5144 0.1605 267.44);
--chart-1: oklch(0.9214 0.0248 257.65);
--chart-2: oklch(0.7597 0.0804 267.01);
--chart-3: oklch(0.6083 0.1247 272.72);
--chart-4: oklch(0.5144 0.1605 267.44);
--chart-5: oklch(0.2571 0.1161 272.24);
--sidebar: oklch(0 0 0);
--sidebar-foreground: oklch(1 0 0);
--sidebar-primary: oklch(0.6144 0.1605 267.44);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604);
--sidebar-accent: oklch(0.32 0 0);
--sidebar-accent-foreground: oklch(0.9214 0.0248 257.65);
--sidebar-border: oklch(0.26 0 0);
--sidebar-ring: oklch(0.5144 0.1605 267.44);
--control-fill: color-mix(in oklab, var(--input) 30%, transparent);
--invalid-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 40%, transparent);
}
}