Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Agents
  • Action Bar
  • Audio Recorder
  • Audio VisualizerBetaBeta — the props contract is close to final, but small breaking changes can still land.
  • Chat Input
  • Chat Input Attachment
  • Chat Message
  • Chat Scene
  • Code Block Editor
  • Dynamic NotificationExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.
  • Environment Variables
  • Inline Attachment
  • Markdown Block
  • Task List
  • Thread Rail
  • Tool Call
  • User Ask
Blocks
  • Chat
  • Theme toggle
  1. Guides
  2. Overview
Guide

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.

Keep using shadcn when its existing components already cover the job.
Use shadcn for app-wide primitives and tokens.
Use Refined UI when the surface is agent-specific: chat, tools, attachments, thoughts, markdown, actions, and full scene recipes.
Install source code into the app, then keep editing it like local product code.

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.

Agent surfaces accept plain props and children; they do not require a runtime provider.
Mastra and AI SDK examples show how an app maps runner data into Refined UI props.
Agents expose anatomy-based parts, so customization happens with children instead of large prop bags.
Skins own markup and visual decisions, instead of hiding large changes behind endless variants.
Blocks compose agents into complete recipes, but each agent remains available on its own.

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.

The core color tokens are shadcn's own names (--background through --ring): paste your existing shadcn :root / .dark theme and the library wears it directly.
Refined UI installs its own Button and Collapsible slots under 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.
SSOT + WYSIWYG: each component exists once under 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.

Reach for :has(), :focus-within, sibling combinators, and container/style queries before tracking hover, open, or width in useState or a ResizeObserver.
Let native elements own behavior: the popover attribute, <dialog>, and <details> replace hand-written outside-click, Escape, and focus-trap code.
Size and animate in CSS: field-sizing: content, @starting-style, a 0fr -> 1fr grid collapse, and a mask-image gradient all key to motion tokens.
Progressive enhancement is the contract: guard Limited features behind @supports and keep a JS fallback, so an unsupported browser still gets a correct, static result.

On this page

  • Why it exists
  • How it works
  • How it works with shadcn
  • CSS-first by default