Get Started
Add JDS to a new or existing React project.
Prerequisites
- React 19 with Tailwind CSS v4.
- A
components.jsonfromshadcn init. Next.js App Router is assumed in examples, but nothing depends on it.
Add the registry
Register the @jds namespace in components.json so the CLI knows where to fetch components from.
{
"registries": {
"@jds": "https://jds-ruddy.vercel.app/r/{name}.json"
}
}Install
Add the style
Installs the neutral light and dark themes, status colors, motion keyframes, and the shared icon and motion utilities. To start from your own look, pick a color, base, radius, font and orb in the Customize menu in the header, then choose Use this theme in your app: one command installs the style with your theme.
pnpm dlx shadcn@latest add @jds/styleAdd components
Each component page lists its own command. Dependencies, including other JDS components, come along.
pnpm dlx shadcn@latest add @jds/prompt-input @jds/messageSet the default theme
JDS is designed dark first. With
next-themes, setdefaultTheme="dark"and keep light available. Both themes are complete.
Manual installation
- Open a component page and switch to the Code tab.
- Copy the source into the path shown, for example
components/ai/prompt-input.tsx. - Copy
lib/icons.tsandlib/motion.tsonce. Every component imports them. - Install the npm dependencies listed on the page.
Fonts
Components read three variables: --font-sans for UI text, --font-mono for code and keys, and --font-heading for titles (aliased to sans by default). This site uses Geist and Geist Mono.
import { Geist, Geist_Mono } from "next/font/google"
const sans = Geist({ variable: "--font-sans", subsets: ["latin"] })
const mono = Geist_Mono({ variable: "--font-mono", subsets: ["latin"] })
<html className={`${sans.variable} ${mono.variable}`}>Next.js starters name the variable --font-geist-sans. Rename it to --font-sans or text falls back to the system font.
Using with the AI SDK
PromptInput status and ToolCall states use the AI SDK's strings, so values pass straight through.
const { messages, status, sendMessage, stop } = useChat()
{messages.map((m) => (
<Message key={m.id} from={m.role}>
<MessageContent>
{m.parts.map((part, i) => {
if (part.type === "text") return <Response key={i} isAnimating={status === "streaming"}>{part.text}</Response>
if (part.type === "reasoning") return (
<Reasoning key={i} isStreaming={part.state === "streaming"}>
<ReasoningTrigger />
<ReasoningContent>{part.text}</ReasoningContent>
</Reasoning>
)
if (part.type.startsWith("tool-")) return (
<ToolCall key={i}>
<ToolCallHeader name={part.type.slice(5)} state={part.state} />
</ToolCall>
)
})}
</MessageContent>
</Message>
))}
<PromptInput status={status} onSubmit={({ text }) => sendMessage({ text })}>
<PromptInputTextarea />
<PromptInputToolbar>
<PromptInputTools />
<PromptInputSubmit onStop={stop} />
</PromptInputToolbar>
</PromptInput>Working with coding agents
The registry is plain JSON at https://jds-ruddy.vercel.app/r/{name}.json. With the namespace in components.json, the shadcn MCP server can search and install JDS components from your agent.
- /llms.txt indexes every page, with a Markdown link per component.
- /llms-full.txt has every component's docs and source in one file.
- Copy page, at the top of every page, copies it as Markdown for pasting into a chat.