Get started
Install one component or a complete chat block, then keep the generated files in your app.
Choose the setup
Pick the runner example in the sidebar. Mastra and AI SDK examples show mapping code, while the installed UI works with any runner that can pass props and children. The site-wide skin is a separate choice in the theme editor.
Install agents
Install the agent bundle when you want to compose the chat surface yourself.
npx shadcn@latest add http://127.0.0.1:3000/r/refined/chat.jsonInstall a block
Install the chat block when you want a complete recipe that already composes scene, messages, input, attachments, markdown, tools, and actions.
npx shadcn@latest add http://127.0.0.1:3000/r/refined/chat-block.jsonWire the CSS
npx shadcn add writes the CSS files into app/ but does not import them. Wire them once in globals.css, in this
canonical order, then stamp the skin scope on <html>.
/* app/globals.css */@import "tailwindcss";@import "./refined-ui-theme.css"; /* the token contract + Tailwind bindings */@import "./refined-ui-effects.css"; /* token-driven @utility effects *//* only when a skin pack is installed: */@import "./refined-ui-skin-theme.css"; /* the pack's contract re-values */@import "./refined-ui-skin.css"; /* the pack's own vars + component CSS */:root { } / .dark { } block in your own CSS - the stock shadcn convention. The baseline authors its defaults at zero specificity (:where(:root)), so your values always win; the core color tokens are shadcn's exact names.[data-skin="<id>"], which always outranks the baseline's zero-specificity :where(:root) defaults. Keep the canonical order anyway - Tailwind, baseline theme, effects, then the pack - so "later wins" stays true for anything unscoped.data-skin="<id>" on <html> (or on any container to scope the look to a subtree). Portal-rendered popups re-assert the id on themselves, so floating surfaces stay themed either way.colorScheme forces and locks the .dark class for fixed-scheme skins (Shiki themes, color-scheme, and dark: utilities all key off it), and motion: "reduced" stamps data-motion="reduced".THEME_INIT_SCRIPT in this repo's components/theme.ts is the reference implementation - these docs run it as a beforeInteractive script.Map runner data
Use the examples as mapping references when your data comes from Mastra or AI SDK. Use the base component files directly when your app already maps data into Refined UI contracts.
import { ChatMessage, ChatMessageBody, ChatMessageContent, ChatMessageRow } from "@/components/refined-ui/chat-message";export function Message({ text }: { text: string }) { return ( <ChatMessage from="assistant"> <ChatMessageRow> <ChatMessageBody> <ChatMessageContent>{text}</ChatMessageContent> </ChatMessageBody> </ChatMessageRow> </ChatMessage> );}