Theme it
Pick the pack, re-value the token contract in one artifact, and check the contrast the components actually paint.
Start from the defaults
“No skin” shows the neutral library baseline. Your application owns its theme and can override only the values that need to change. Refined and the other named presets remain optional starting points.
Components and portals render without a skin config or provider. Add your brand through application CSS.
Paint the document, not just the body
Apply bg-background to your document’s <html> element so overscroll and viewport gaps use the active theme.
The Next.js starter includes this root background. Keep the skin and color-mode attributes on the same theme boundary.
Let pages scroll with the window
Set sidebarLayout: "page" in your skin config, or use <Sidebar variant="page"> for one layout.
An explicit variant takes precedence over the skin default. Page removes the sidebar divider and inset
frame while retaining the fixed desktop navigation, collapse controls, resize rail, and mobile drawer.
Keep SidebarProvider in normal document flow: its default minimum height fills the viewport without
limiting the page height. Render content directly inside SidebarInset; do not add h-svh, an
overflow-constrained ancestor, or a full-screen ScrollArea around the main content. SidebarContent
can still scroll the navigation independently.
import type { ReactNode } from "react";import { Sidebar, SidebarContent, SidebarInset, SidebarProvider, SidebarTrigger,} from "@/components/control-ui/ui/sidebar";export function PageLayout({ navigation, children }: { navigation: ReactNode; children: ReactNode }) { return ( <SidebarProvider> <Sidebar variant="page"> <SidebarContent>{navigation}</SidebarContent> </Sidebar> <SidebarInset> <header className="p-4"> <SidebarTrigger /> </header> {children} </SidebarInset> </SidebarProvider> );}Omit variant="page" when the skin should choose the layout. The sidebar component playground confines
every variant to its preview frame; use the composition above for native window scrolling.
Keep frequent feedback immediate
Hover colors and hover-following highlights update immediately, as do desktop sidebar toggles. Press feedback, selection indicators, and popup entrances retain their motion tokens and respect reduced-motion preferences.
Group neighboring tooltips in one TooltipProvider: the first hover waits 500 ms, then neighboring tooltips open
immediately within Base UI’s 400 ms grouping window. Use the provider’s delay and timeout props when your
interaction needs different timing.
One artifact owns the theme
A theme is one file — <short-name>.control-ui-theme.json, format control-ui-theme/v1 — with tokens split into
shared, light, and dark. Color-valued tokens go in light and dark; everything else in shared. A token
left out inherits the base skin, so the artifact composes onto the pack instead of forking it.
Contrast is part of the theme
Contrast is a property of the theme, not a follow-up audit. Normal and small text clears 4.5:1 after alpha compositing in both modes; focus indicators and control boundaries clear 3:1.
The accessibility page checks the canonical colors plus what the components actually paint — popups, badges, active tabs — and the same checks run from the CLI, on every commit, over the baseline and every preset mode.