Github

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

background
primary
secondary
muted
destructive
sidebar

Chart

--chart-1--chart-5 are tokens only. The chart on /components/chart uses them.

chart-1
chart-2
chart-3
chart-4
chart-5

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: --background through --ring (canvas, card, popover, primary, secondary, muted, accent, destructive, border, input).
  • Sidebar chrome, if you want it: --sidebar through --sidebar-ring.
  • Charts: --chart-1--chart-5.
  • Radius: --radius (the --radius-sm--radius-4xl calcs 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 theme
Light and Dark tokens, scoped to this preview.
chart-1
chart-2
chart-3
chart-4
chart-5
/* 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 theme
Light and Dark tokens, scoped to this preview.
chart-1
chart-2
chart-3
chart-4
chart-5
/* 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 theme
Light and Dark tokens, scoped to this preview.
chart-1
chart-2
chart-3
chart-4
chart-5
/* 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);
	}
}