Skinning Refined UI
A skin is DATA, not a fork: tokens, per-slot classes and decorative adornments that restyle the ONE refined library. Components never change per skin — every slot composes cn(recipe, skinSlot(slot, ctx), className), so precedence is tailwind-merge argument order. This page is the skin AUTHOR's reference: pack anatomy, the token contract, and the enforced requirements.
Not sure a skin is even the right tool? The customization ladder in the Architecture guide places every "make it different" request on one of eight rungs — with what each rung costs an app that never uses it. This page picks up once the answer is a skin.
Slot vs skin.css
Where a skin author paints each property, in order of preference.
The token contract
Every custom property a skin may re-value, rendered straight from lib/theme-contract.ts — the same module the coverage test enforces, so this reference can never drift from the CSS.
--backgroundColorBase surface color (panels, bubbles read it via bg-background).--foregroundColorDefault text color on --background.--cardColorElevated card surface.--card-foregroundColorText color on --card.--popoverColorFloating surface base (popover / menu / select / dialog).--popover-foregroundColorText color on --popover.--primaryColorTHE brand color; primary action surfaces route through it.--primary-foregroundColorText color on --primary.--mutedColorSubdued fill for quiet surfaces.--muted-foregroundColorSecondary / meta text color.--secondaryColorSecondary action fill (assistant bubble in chat skins).--secondary-foregroundColorText color on --secondary.--accentColorHover / selection highlight fill.--accent-foregroundColorText color on --accent.--destructiveColorDestructive action color.--destructive-foregroundColorText color on --destructive.--borderColorHairline border color (carries --ring-opacity).--inputColorForm field border color.--ringColorFocus ring color.--canvasColorThe page paper the scene/panels float on — a level BELOW --background.--font-sansTypographyTypeface for the whole UI.--font-monoTypographyMonospace face (code, kbd).--radiusRadiusTHE single radius knob; the whole scale multiplies from it.--duration-fastMotionFast tempo (hover, color).--duration-baseMotionBase tempo (menus, indicators).--duration-slowMotionSlow tempo (panel/message entrances).Advanced — Color92 tokens›
--ring-opacityColorAlpha of the border/ring hairlines; 0 = borderless.--popup-item-foregroundColorText color of popup (menu/select) rows.--popup-item-icon-foregroundColorIcon color inside popup rows.--popup-item-highlight-backgroundColorHover/highlight fill of popup rows.--badge-neutralColorSoft neutral badge background.--badge-neutral-foregroundColorText color on the neutral badge.--badge-neutral-borderColorBorder of the outline neutral badge variant.--badge-neutral-hoverColorHover background of neutral badge links/buttons.--badge-slateColorSoft slate badge background.--badge-slate-foregroundColorText color on the slate badge.--badge-slate-borderColorBorder of the outline slate badge variant.--badge-slate-hoverColorHover background of slate badge links/buttons.--badge-grayColorSoft gray badge background.--badge-gray-foregroundColorText color on the gray badge.--badge-gray-borderColorBorder of the outline gray badge variant.--badge-gray-hoverColorHover background of gray badge links/buttons.--badge-zincColorSoft zinc badge background.--badge-zinc-foregroundColorText color on the zinc badge.--badge-zinc-borderColorBorder of the outline zinc badge variant.--badge-zinc-hoverColorHover background of zinc badge links/buttons.--badge-stoneColorSoft stone badge background.--badge-stone-foregroundColorText color on the stone badge.--badge-stone-borderColorBorder of the outline stone badge variant.--badge-stone-hoverColorHover background of stone badge links/buttons.--badge-redColorSoft red badge background.--badge-red-foregroundColorText color on the red badge.--badge-red-borderColorBorder of the outline red badge variant.--badge-red-hoverColorHover background of red badge links/buttons.--badge-orangeColorSoft orange badge background.--badge-orange-foregroundColorText color on the orange badge.--badge-orange-borderColorBorder of the outline orange badge variant.--badge-orange-hoverColorHover background of orange badge links/buttons.--badge-amberColorSoft amber badge background.--badge-amber-foregroundColorText color on the amber badge.--badge-amber-borderColorBorder of the outline amber badge variant.--badge-amber-hoverColorHover background of amber badge links/buttons.--badge-yellowColorSoft yellow badge background.--badge-yellow-foregroundColorText color on the yellow badge.--badge-yellow-borderColorBorder of the outline yellow badge variant.--badge-yellow-hoverColorHover background of yellow badge links/buttons.--badge-limeColorSoft lime badge background.--badge-lime-foregroundColorText color on the lime badge.--badge-lime-borderColorBorder of the outline lime badge variant.--badge-lime-hoverColorHover background of lime badge links/buttons.--badge-greenColorSoft green badge background.--badge-green-foregroundColorText color on the green badge.--badge-green-borderColorBorder of the outline green badge variant.--badge-green-hoverColorHover background of green badge links/buttons.--badge-emeraldColorSoft emerald badge background.--badge-emerald-foregroundColorText color on the emerald badge.--badge-emerald-borderColorBorder of the outline emerald badge variant.--badge-emerald-hoverColorHover background of emerald badge links/buttons.--badge-tealColorSoft teal badge background.--badge-teal-foregroundColorText color on the teal badge.--badge-teal-borderColorBorder of the outline teal badge variant.--badge-teal-hoverColorHover background of teal badge links/buttons.--badge-cyanColorSoft cyan badge background.--badge-cyan-foregroundColorText color on the cyan badge.--badge-cyan-borderColorBorder of the outline cyan badge variant.--badge-cyan-hoverColorHover background of cyan badge links/buttons.--badge-skyColorSoft sky badge background.--badge-sky-foregroundColorText color on the sky badge.--badge-sky-borderColorBorder of the outline sky badge variant.--badge-sky-hoverColorHover background of sky badge links/buttons.--badge-blueColorSoft blue badge background.--badge-blue-foregroundColorText color on the blue badge.--badge-blue-borderColorBorder of the outline blue badge variant.--badge-blue-hoverColorHover background of blue badge links/buttons.--badge-indigoColorSoft indigo badge background.--badge-indigo-foregroundColorText color on the indigo badge.--badge-indigo-borderColorBorder of the outline indigo badge variant.--badge-indigo-hoverColorHover background of indigo badge links/buttons.--badge-violetColorSoft violet badge background.--badge-violet-foregroundColorText color on the violet badge.--badge-violet-borderColorBorder of the outline violet badge variant.--badge-violet-hoverColorHover background of violet badge links/buttons.--badge-purpleColorSoft purple badge background.--badge-purple-foregroundColorText color on the purple badge.--badge-purple-borderColorBorder of the outline purple badge variant.--badge-purple-hoverColorHover background of purple badge links/buttons.--badge-fuchsiaColorSoft fuchsia badge background.--badge-fuchsia-foregroundColorText color on the fuchsia badge.--badge-fuchsia-borderColorBorder of the outline fuchsia badge variant.--badge-fuchsia-hoverColorHover background of fuchsia badge links/buttons.--badge-pinkColorSoft pink badge background.--badge-pink-foregroundColorText color on the pink badge.--badge-pink-borderColorBorder of the outline pink badge variant.--badge-pink-hoverColorHover background of pink badge links/buttons.--badge-roseColorSoft rose badge background.--badge-rose-foregroundColorText color on the rose badge.--badge-rose-borderColorBorder of the outline rose badge variant.--badge-rose-hoverColorHover background of rose badge links/buttons.Advanced — Typography34 tokens›
--font-bodyTypographyFont ROLE for body/UI text; defaults to --font-sans.--font-displayTypographyFont ROLE for headings; defaults to --font-sans.--text-microTypography10px rung — kbd, badge counters, dense numeric meta.--text-captionTypography11px rung — overlines, timestamps, group labels.--text-labelTypography12px rung — form labels + small chrome.--text-bodyTypography14px rung — DEFAULT body & control text.--text-body-lgTypography16px rung — emphasized / larger body.--text-heading-4TypographySmallest heading rung (15px).--text-heading-4--line-heightTypographyLine-height paired onto text-heading-4.--text-heading-4--font-weightTypographyWeight paired onto text-heading-4.--text-heading-3TypographyHeading rung (18px).--text-heading-3--line-heightTypographyLine-height paired onto text-heading-3.--text-heading-3--font-weightTypographyWeight paired onto text-heading-3.--text-heading-2TypographyHeading rung (22px).--text-heading-2--line-heightTypographyLine-height paired onto text-heading-2.--text-heading-2--font-weightTypographyWeight paired onto text-heading-2.--text-heading-1TypographyLargest content heading (30px — in-page / markdown h1).--text-heading-1--line-heightTypographyLine-height paired onto text-heading-1.--text-heading-1--font-weightTypographyWeight paired onto text-heading-1.--text-heading-1--letter-spacingTypographyTracking paired onto text-heading-1.--text-displayTypographyDisplay rung above h1 (36px — page titles, heroes).--text-display--line-heightTypographyLine-height paired onto text-display.--text-display--font-weightTypographyWeight paired onto text-display.--text-display--letter-spacingTypographyTracking paired onto text-display.--text-metaTypographyLegacy alias of --text-caption (11px).--text-title-smTypographyLegacy alias of --text-heading-4.--text-title-sm--line-heightTypographyLine-height paired onto text-title-sm.--text-title-sm--font-weightTypographyWeight paired onto text-title-sm.--text-title-mdTypographyLegacy alias of --text-heading-3.--text-title-md--line-heightTypographyLine-height paired onto text-title-md.--text-title-md--font-weightTypographyWeight paired onto text-title-md.--text-title-lgTypographyLegacy alias of --text-heading-2.--text-title-lg--line-heightTypographyLine-height paired onto text-title-lg.--text-title-lg--font-weightTypographyWeight paired onto text-title-lg.Advanced — Radius19 tokens›
--radius-controlRadiusShared control corner (button, trigger, field, chip); ×2 from --radius.--radius-smRadiusScale rung: --radius × 0.6.--radius-mdRadiusScale rung: --radius × 0.8.--radius-lgRadiusScale rung: --radius × 1.--radius-xlRadiusScale rung: --radius × 1.4.--radius-2xlRadiusScale rung: --radius × 1.6.--radius-fieldRadiusUser bubble / composer shell corner; --radius × 2.2.--radius-panelRadiusCode / markdown panel corner; --radius × 2.6.--radius-sceneRadiusScene frame / large media corner; --radius × 2.8.--corner-shapeRadiusProgressive corner reshape (round | squircle | scoop | …).--corner-shape-controlRadiusCorner shape for controls; defaults to --corner-shape.--corner-shape-popoverRadiusCorner shape for floating surfaces; defaults to --corner-shape.--corner-shape-panelRadiusCorner shape for panels; defaults to --corner-shape.--corner-radius-fitRadiusFallback radius shrink where corner-shape: squircle is unsupported.--radius-popup-itemRadiusSelect/menu row corner; derived from --radius-control.--radius-popup-item-fitRadiusRow corner clamped to half the row height (browser render cap).--radius-popoverRadiusPopup container corner, concentric with the fitted row corner.--nest-safeRadiusSub-pixel guard for rounded children inside clipped rounded containers.--nest-corner-ratioRadiusCorner-fit ratio (2 + √2) capping panel corners near inset controls.Advanced — Shadow10 tokens›
--shadow-colorShadowHue every shadow is tinted with.--shadow-highlightShadowInner top light painted along raised surfaces' top edge (carries its resting alpha).--shadow-sizeShadowGlobal geometry multiplier: 1 = default depth, 0 = flat.--shadow-opacityShadowGlobal alpha multiplier: 1 = default density, 0 = invisible.--shadow-yShadowVertical bias: 0 = centered, 1 = default bottom cast.--shadow-control-multiplierShadowElevation tier: controls.--shadow-panel-multiplierShadowElevation tier: panels.--shadow-popover-multiplierShadowElevation tier: floating popovers.--shadow-modal-multiplierShadowElevation tier: dialogs and sheets.--shadow-ambient-multiplierShadowElevation tier: ambient scene lift.Advanced — Motion2 tokens›
--ease-standardMotionDefault easing curve for color/text transitions.--ease-emphasizedMotionEmphasized curve for entrances and larger moves.Advanced — Surface6 tokens›
--popover-opacitySurfaceFloating-surface translucency; <1 + blur = frosted glass.--backdrop-blur-popoverSurfaceBackdrop blur behind floating surfaces.--overlay-opacitySurfaceModal overlay (dialog backdrop) dim strength.--backdrop-blur-overlaySurfaceBackdrop blur of the modal overlay.--scroll-fade-sizeSurfaceEdge-fade depth of scrollable surfaces; 0 = hard edges.--popup-item-disabled-opacitySurfaceOpacity of disabled popup rows.Advanced — Layout8 tokens›
--popover-paddingLayoutGap between popup container edge and rows (drives concentric corners).--padding-xLayoutHorizontal content density of rounded surfaces (bubble, composer).--padding-yLayoutVertical content density of rounded surfaces.--control-hLayoutTHE base control height (md); the ramp derives from it.--control-h-xsLayoutDerived control height: xs (×0.78, px-snapped).--control-h-smLayoutDerived control height: sm (×0.89, px-snapped).--control-h-mdLayoutControl height alias for the md base.--control-h-lgLayoutDerived control height: lg (×1.11, px-snapped).Skin requirements — the do-not list
What a pack must and must not do. Every rule is enforced by a test, so a violating pack fails the build before it ships.
Generate from a seed
Author a theme skin's tokens from one seed instead of hand-writing every CSS var — opt-in, overrides always win.
defineSkinTokens fans one seed (hue, saturation, radius, density) out into a coherent brand + surface + foreground ramp; explicit light/dark values win over the generated ones. Drop a tokens.ts exporting { skinId, skinTokens } into a pack and bun run sync writes its theme.css scoped to [data-skin] — the same shape the pack would ship hand-authored. It is deterministic, so the generated file passes the --check drift guard. The packs shipped here are hand-authored, so none ships a tokens.ts today; add one to switch a pack onto the factory.
// src/registry/skin-packs/ocean/tokens.tsimport { defineSkinTokens } from "@/src/registry/lib/define-skin-tokens";export const skinId = "ocean";export const skinTokens = defineSkinTokens({ seed: { hue: 205, saturation: 60, radius: 12, density: "regular" }, // Explicit overrides win over anything the ramp generates: light: { "--canvas": "oklch(0.9691 0.0051 238.437)" },});Adornments
JSX at named anchors — decorative chrome, or behavioral fx layers.
Additive, render zero DOM when absent, never gate library behavior. Decorative anchors (window titlebars, window controls) take plain aria-hidden JSX. Behavioral anchors (like chat-input:send-layer) take a (ctx) => JSX render prop whose ctx carries plain render-time values — this is how a pack activates an anchored extension (send-aurora). Interactive values live in a separate "use client" file the pack ships, so skin.config itself stays RSC-pure.
Motion flag
One boolean, zero JavaScript.
motion: "reduced" stamps data-motion="reduced", which collapses --duration-fast/base/slow to 0 — every cva transition, Base UI enter/exit and the shimmer/ripple keyframes flatten at once. The theme editor also exposes a manual "Reduce motion" toggle.
Gotcha — custom @utility and twMerge
A pack's own @utility (xp-bevel-up, xp-scrollbar…) is unknown to tailwind-merge, so it is NOT evicted by group when a caller passes a conflicting utility. Two exclusive slots (skeleton-paint, chat-message-streaming) resolve skinSlot(...) ?? fallback for exactly this reason.
Skins
Each pack's tokens, skin.css and config, ready to read and install.