Guide
shadcn compatibility
shadcn registry, token, and ownership conventions without writing to components/ui.
Compatible by contract
Control UI uses shadcn registry manifests and core token names. Its source installs under components/control-ui/*
without writing to components/ui/*. Component props are defined by Control UI and are not promised as drop-in
replacements for same-named components.
components/ui/*
your existing shadcn source
shadcn registry manifests
shared core token names
components/control-ui/*
installed Control UI source
Control UI never writes to components/ui/*
Bring an existing theme
The core color contract uses shadcn's token names — --background, --foreground, --card, --popover,
--primary, --secondary, --muted, --accent, --destructive, --border, --input, --ring. Existing values
can seed a Control UI skin, but the skin must complete the wider contract itself; core supplies no brand defaults.
[data-skin="my-skin"][data-skin] { --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --primary: oklch(0.6131 0.2067 283.83); --primary-foreground: oklch(1 0 0); --radius: 0.625rem;}.dark[data-skin="my-skin"][data-skin],:where(.dark) [data-skin="my-skin"][data-skin] { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0);}/* Continue with every remaining Control UI contract token. */Core provides neutral defaults. Optional scoped skins use
SkinProvider and a matching data-skin boundary.Every skin resolves the full contract — color, typography, radius, shadow, motion, surface — in both modes.
A pack declares its tokens under
[data-skin="id"][data-skin], which out-specifies a bare :root on the same element. Your old :root values go dead — delete them. The exception is names no skin declares (--chart-* and other app extensions): those keep painting beside the skin, so re-point them at skin tokens. To override a pack token on purpose, match the weight: :root[data-skin].An app
@theme block never goes dead: Tailwind merges every @theme and the last declaration wins. Redeclaring mapped keys — --color-*, --radius-sm through --radius-2xl, --font-* — after the Control UI imports detaches those utilities from the skin. Keep your @theme to keys Control UI does not map; scripts/control-ui-doctor.mjs in the installed directory reports any collision.