Overview
Refined UI is a registry-first layer for production AI interfaces built on top of shadcn-style ownership.
Why it exists
shadcn made owned UI primitives feel normal, and Refined UI would not exist without that work. This is not a replacement for shadcn; it is the AI-specific layer for the surfaces product teams still rebuild by hand: message anatomy, composer behavior, tool states, action bars, streaming surfaces, and complete chat scenes.
How it works
The UI layer is runtime-agnostic. Skins install source for the visible surface, runner examples stay readable, and the docs show code read from the real registry source.
How it works with shadcn
Default is the shadcn-compatibility SOURCE: it composes the host shadcn primitives directly through registryDependencies.
shadcn compatibility is a CONTRACT the library keeps, not a second source tree: the core tokens carry shadcn's exact
names, the components keep shadcn's idioms, and the library installs beside your existing components/ui/* without ever
writing to it. The shadcn compatibility guide covers the whole story.
--background through --ring): paste your existing shadcn :root / .dark theme and the library wears it directly.components/refined-ui/ui/*; it never touches the host components/ui/*.components/ui/* belongs to the user: the host app keeps ownership, and both trees coexist in one app.src/registry/sources/*, and every preview renders the exact installed fixture so what you see is byte-for-byte what add r/refined/* installs.CSS-first by default
Refined UI is CSS-first: interaction, sizing, and motion live in modern CSS and native platform elements before they become React state or effects. Declarative CSS is server-rendered, survives hydration, honours the reduce-motion tokens, and ships zero JavaScript - so a skin can restyle it and a slow device still runs it. JavaScript is for logic that is genuinely stateful or asynchronous, not for a class a selector could toggle.
:has(), :focus-within, sibling combinators, and container/style queries before tracking hover, open, or width in useState or a ResizeObserver.popover attribute, <dialog>, and <details> replace hand-written outside-click, Escape, and focus-trap code.field-sizing: content, @starting-style, a 0fr -> 1fr grid collapse, and a mask-image gradient all key to motion tokens.@supports and keep a JS fallback, so an unsupported browser still gets a correct, static result.