Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Skins
  • How to build a skin
  • Refined
  • Windows XP
  • Liquid metal
  • Rig
  • Flat
  • Modern Apple
  • Cuicui
  • Linear
  1. Skins
  2. Skinning Refined UI
Skins

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.

token firstA value the contract already exposes (radius, color) goes in theme.css; a value it doesn't (an invented var) goes in skin.css, never theme.css.
skinSlotWhen the property is ALSO painted by the cva recipe (twMerge would evict a bare CSS rule) or reacts to slot state; also the channel to APPLY a pack's own @utility.
skin.cssRoot inheritance, descendant families, keyframes; never on a property the recipe paints as a utility.
neverNo un-layered CSS. Never re-style a slot skin.config can already reach, and never re-implement a library recipe in skin.css — re-value its component-local vars instead.

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.

Core — the 26 tokens a skin typically re-values first
--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.

contract only in theme.csstheme.css re-values contract names and nothing else; an invented var belongs in skin.css. Enforced by theme-contract-coverage.test.ts, which also pins lib/theme-contract.ts bidirectionally to the baseline theme.css.
no @theme in a pack@theme merges globally across co-compiled packs, so a pack can never own bindings — scale intent is authored as raw scoped tokens; the @theme block belongs to the refined baseline alone. Enforced per pack.
light/dark parityEvery contract color token is declared for both modes (or mode-independent). A one-sided color leaks the other mode's baseline value into the skin. Enforced per pack.
no component CSS in theme.css@layer components, @utility, @keyframes, and anatomy selectors live in skin.css — theme.css stays a pure token block. Enforced per pack.
skin.css never redeclares the contractA contract name re-valued in skin.css hides the change from the theme editor and this token reference; contract names are theme.css territory. Enforced per pack.
scope anatomy, never host elementsComponent selectors in skin.css carry [data-ui="agent"]; never skin bare host elements (code, button, input) under [data-skin]. Root skin blocks declare variables only. Enforced per pack.
declared intents, mirroredcolorScheme locks the page mode to a fixed-scheme skin and motion: "reduced" collapses --duration-* through data-motion — never animation: none on finite animations. Both flags are mirrored in components/theme.ts for the pre-paint script; theme-color-scheme-lock.test.ts fails on drift.
extensions attach by anatomyA runtime discovers controls via [data-ui="agent"][data-control="true"], gates its observers on the active skin, and tears down cleanly. skin.config can never import one (RSC-pure) — the pack documents the runtime and the app mounts it in its layout.

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.ts
import { 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.

RefinedCompact, calm default skin for Refined UI.ThemeWindows XPWindows XP-inspired Luna tokens, bevels, and titlebar details.AdvancedLiquid metalPolished metal skin with a WebGL shader control surface.AdvancedRigBrutalist skin with coral accents, squared corners, and dense typography.ThemeFlatNeutral reset skin with square corners, no shadows, and instant motion.ThemeModern AppleLiquid-Glass Apple skin: translucent surfaces, refined backdrop blur, white rims, transparent inputs, and squircle corners.AdvancedCuicuiCuicui-inspired shell skin with fixed grain, a docked w-80 sidebar, a neutral main container, and the send-aurora anchored extension on ChatInput (skin.config fills the chat-input:send-layer anchor).AdvancedLinearLinear-inspired skin: indigo brand on a cool neutral ramp, a flat 13px chrome band, 4px radius, hairline borders instead of elevation, and pill-shaped filled actions.Advanced

On this page

  • Slot vs skin.css
  • Token contract
  • Requirements
  • Generate from a seed
  • Adornments
  • Motion flag
  • Gotcha
  • Skins