Installation

Everything here assumes a React project with Tailwind v4 and shadcn/ui already set up. Components are copied into your repo, so there is no runtime package to keep in sync.

Prerequisites

  • A components.json at the project root — run npx shadcn@latest init if you do not have one.
  • Tailwind CSS v4 with the shadcn CSS variables defined (init writes them for you).
  • React 19, and Node 20.9 or newer for the CLI.

The components import cn() from @/lib/utils and resolve shadcn primitives through the aliases in components.json. Missing primitives (dropdown menu, context menu, collapsible) are pulled in automatically.

Install the kit

The chat block installs a working chat surface plus every atom it composes.

npx shadcn@latest add miskibin/chat-components/chat

Install single atoms

Nothing here needs the block. Add only what you use — each item pulls its own dependencies.

npx shadcn@latest add miskibin/chat-components/chat-input
npx shadcn@latest add miskibin/chat-components/prompt-suggestions
npx shadcn@latest add miskibin/chat-components/todo-list
npx shadcn@latest add miskibin/chat-components/chat-navbar
npx shadcn@latest add miskibin/chat-components/resizable
npx shadcn@latest add miskibin/chat-components/message
npx shadcn@latest add miskibin/chat-components/message-list
npx shadcn@latest add miskibin/chat-components/message-parts
npx shadcn@latest add miskibin/chat-components/ask-question
npx shadcn@latest add miskibin/chat-components/plan-card
npx shadcn@latest add miskibin/chat-components/message-markdown
npx shadcn@latest add miskibin/chat-components/render-error-boundary
npx shadcn@latest add miskibin/chat-components/change-summary
npx shadcn@latest add miskibin/chat-components/file-preview
npx shadcn@latest add miskibin/chat-components/diff-view
npx shadcn@latest add miskibin/chat-components/file-tree
npx shadcn@latest add miskibin/chat-components/file-icon
npx shadcn@latest add miskibin/chat-components/generation-status
npx shadcn@latest add miskibin/chat-components/folder-picker
npx shadcn@latest add miskibin/chat-components/model-picker
npx shadcn@latest add miskibin/chat-components/mode-picker
npx shadcn@latest add miskibin/chat-components/context-meter
npx shadcn@latest add miskibin/chat-components/theme-toggle
npx shadcn@latest add miskibin/chat-components/chat-sidebar
npx shadcn@latest add miskibin/chat-components/sidebar-item
npx shadcn@latest add miskibin/chat-components/sidebar-dnd
npx shadcn@latest add miskibin/chat-components/sidebar-drop-zones
npx shadcn@latest add miskibin/chat-components/sidebar-resize-rail
npx shadcn@latest add miskibin/chat-components/use-click-outside

Markdown rendering

Message Markdown renders answers with Streamdown (GFM, Shiki, Mermaid, KaTeX). Those packages ship Tailwind utility classes inside their own dist files, so two build settings are required — without them the markdown renders unstyled.

1. Tailwind sources

Add these next to your @import "tailwindcss" so the utilities are generated.

app/globals.css
@import "tailwindcss";
@import "streamdown/styles.css";

@source "../node_modules/streamdown/dist/*.js";
@source "../node_modules/@streamdown/code/dist/*.js";
@source "../node_modules/@streamdown/mermaid/dist/*.js";
@source "../node_modules/@streamdown/math/dist/*.js";

2. Transpile the packages

On Next.js, add them to the config.

next.config.ts
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  transpilePackages: [
    "streamdown",
    "@streamdown/code",
    "@streamdown/mermaid",
    "@streamdown/math",
    "mermaid",
  ],
}

export default nextConfig

Providers

ThemeToggle and the markdown renderer read the resolved theme from next-themes, so mount the provider once at the root. The examples in these docs also use sonner for toasts — optional, but the Toaster has to be mounted if you copy them verbatim.

npm install next-themes sonner
app/layout.tsx
import { ThemeProvider } from "next-themes"
import { Toaster } from "sonner"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body suppressHydrationWarning>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          {children}
        </ThemeProvider>
        <Toaster position="top-right" richColors />
      </body>
    </html>
  )
}

Layout

The chat surface fills its parent and manages its own inner scrolling, so give the parent an explicit height and let the message list own the overflow.

<div className="flex h-svh min-h-0 flex-col overflow-hidden">
  <ChatNavbar title={title} />
  <MessageList className="flex-1" messages={messages} />
  <ChatInput onSend={send} />
</div>