guides
Getting started
Add your first component to a React project and have a working chat input in a few minutes.
requirements
- React 19 and a framework that supports it, such as Next.js or Vite.
- Tailwind CSS v4.
- A project set up with the shadcn CLI. If you do not have one yet, run npx shadcn@latest init. It creates components.json, the cn helper and the base styles.
turn is a registry, not a package. The CLI copies the source into your project and installs the small number of dependencies each component needs (Base UI, and for a few components Shiki, marked or react-markdown).
1. add the theme
The components read eight color tokens, and one of them behaves differently from a stock shadcn theme: accent is the primary action color here, not a pale highlight. Install the theme to set all eight, or skip this step and define them yourself. See theming.
npx shadcn@latest add https://turnui.xyz/r/theme.json2. add components
Each command also installs the components it depends on. You can pass several at once.
npx shadcn@latest add \
https://turnui.xyz/r/message.json \
https://turnui.xyz/r/prompt-composer.jsonFiles land in components/ui and hooks, using the aliases from your components.json. They are yours from that point: edit the markup, tokens and behavior freely.
3. build a chat
A complete page with a message list and a composer. It echoes your message back, so you can see everything working before you connect a model.
"use client";
import { useState } from "react";
import { Message, MessageContent } from "@/components/ui/message";
import { PromptComposer } from "@/components/ui/prompt-composer";
type Turn = { role: "user" | "assistant"; text: string };
export default function Page() {
const [turns, setTurns] = useState<Turn[]>([]);
return (
<main className="mx-auto flex h-dvh max-w-2xl flex-col p-4">
<div role="log" aria-live="polite" aria-label="Conversation" tabIndex={0} className="flex-1 space-y-4 overflow-y-auto outline-none focus-visible:ring-2 focus-visible:ring-ring">
{turns.map((t, i) => (
<Message key={i} role={t.role}>
<MessageContent>{t.text}</MessageContent>
</Message>
))}
</div>
<PromptComposer
onSubmit={(text) =>
setTurns((all) => [...all, { role: "user", text }, { role: "assistant", text: "You said: " + text }])
}
/>
</main>
);
}The container has role="log" and aria-live="polite" so screen readers announce new messages, and tabIndex={0} so keyboard users can scroll it. Enter sends, Shift+Enter adds a line.
next
- Connect a real model with the Vercel AI SDK.
- Add attachments, slash commands and a model picker: they all plug into the Prompt Composer.
- Show agent work with Plan, Tool Call and Approval Prompt.