Back to .md Directory

Chat UI Components & Infrastructure Reference

Catalogues available shadcn/ui components, CSS theme tokens, animation infrastructure, and chat UI composition patterns for a production app.

May 2, 2026
0 downloads
4 views
ai
View source

What this file does

Catalogues available shadcn/ui components, CSS theme tokens, animation infrastructure, and chat UI composition patterns for a production app.

When to use it

  • You need a quick reference of all shadcn/ui components in your project
  • You want to understand the OKLch color token system and dark mode setup
  • You are building a chat interface and need composition examples
  • You need to know which animations and typography plugins are available

Assumes this stack

ReactTypeScriptTailwind CSSshadcn/uiFramer Motionshiki

Chat UI Components & Infrastructure Reference

Available shadcn/UI Components

All components are in src/components/ui/ and ready to use:

Core Layout & Structure

  • card.tsx - Card containers with bg-card styling
  • dialog.tsx - Modal dialogs with data-open/data-closed state animations
  • alert-dialog.tsx - Confirmation dialogs
  • sheet.tsx - Slide-out panels
  • sidebar.tsx - Pre-styled sidebar with special accent handling

Form & Input

  • input.tsx - Text input fields
  • textarea.tsx - Multi-line text input
  • label.tsx - Form labels
  • checkbox.tsx - Checkbox controls
  • radio-group.tsx - Radio button groups
  • switch.tsx - Toggle switches
  • select.tsx - Dropdown selects with animation support
  • toggle.tsx / toggle-group.tsx - Toggle buttons (grouped)

Content & Display

  • badge.tsx - Badge labels
  • alert.tsx - Alert boxes
  • skeleton.tsx - Loading placeholders with shimmer animation
  • separator.tsx - Visual separators
  • scroll-area.tsx - Custom scrollable areas

Menus & Dropdowns

  • dropdown-menu.tsx - Context menus with fade-in/out animations
  • popover.tsx - Floating popovers
  • tooltip.tsx - Tooltips with data-open/data-closed animation (fade-in-0, zoom-in-95)
  • accordion.tsx - Collapsible sections
  • command.tsx - Command palette / search interface

Custom Components

  • button.tsx - Base button with CVA variants (default, destructive, outline, secondary, ghost, link)
  • LoadingBar.tsx - Marquee animation progress bar (animate-marquee)
  • ColorPicker.tsx - Custom color picker
  • NumberInput.tsx - Numeric input
  • SimpleAvatar.tsx - Simple avatar display

CSS Variable & Color Token System

Theme Variables (OKLch Color Space)

Located in src/styles/globals.css with automatic light/dark mode switching via .dark class:

Light Mode (Default)

--background: oklch(1 0 0) /* Pure white */
  --background-lighter: oklch(0.995 0 0) --background-darker: oklch(0.955 0 0)
  --background-darkest: oklch(0.925 0 0) --foreground: oklch(0.145 0 0)
  /* Dark text */ --card: oklch(1 0 0) /* White cards */
  --primary: oklch(0.205 0 0) /* Dark buttons */ --secondary: oklch(0.97 0 0)
  /* Light backgrounds */ --accent: oklch(0.97 0 0) --muted: oklch(0.97 0 0)
  --destructive: oklch(0.577 0.245 27.325) /* Red/Orange hue */
  --border: oklch(0.922 0 0) --input: oklch(0.922 0 0)
  --sidebar: oklch(0.96 0 0) --sidebar-accent: oklch(0.92 0 0);

Dark Mode (.dark class)

--background: oklch(0.145 0 0) /* Dark background */
  --foreground: oklch(0.985 0 0) /* Light text */ --card: oklch(0.145 0 0)
  /* Dark cards */ --primary: oklch(0.985 0 0) /* Light buttons */
  --sidebar: oklch(0.1 0 0) /* Very dark sidebar */;

Semantic Colors

  • --primary / --primary-foreground - Primary actions & buttons
  • --secondary / --secondary-foreground - Secondary elements
  • --accent / --accent-foreground - Emphasized elements
  • --muted / --muted-foreground - Disabled/secondary text
  • --destructive / --destructive-foreground - Danger actions (red/orange)
  • --card / --card-foreground - Card backgrounds & text
  • --border / --input - Borders & input backgrounds
  • --ring - Focus ring colors

Chart/Data Visualization Colors

--chart-1: oklch(0.646 0.222 41.116) /* Orange/Yellow */
  --chart-2: oklch(0.6 0.118 184.704) /* Blue */
  --chart-3: oklch(0.398 0.07 227.392) /* Dark Blue */
  --chart-4: oklch(0.828 0.189 84.429) /* Green/Yellow */
  --chart-5: oklch(0.769 0.188 70.08) /* Orange */;

Radius & Spacing

--radius: 0.625rem /* Base border-radius (~10px) */
  --radius-sm: calc(--radius - 4px) /* ~6px */ --radius-md: calc(--radius - 2px)
  /* ~8px */ --radius-lg: var(--radius) /* ~10px */
  --radius-xl: calc(--radius + 4px) /* ~14px */;

Sidebar Specific

--sidebar: oklch(0.96 0 0) --sidebar-foreground: oklch(0.145 0 0)
  --sidebar-primary: oklch(0.145 0 0) --sidebar-primary-foreground: oklch(1 0 0)
  --sidebar-accent: oklch(0.92 0 0) /* Hover/active state */
  --sidebar-accent-foreground: oklch(0.145 0 0) --sidebar-border: oklch(0.9 0 0)
  --sidebar-ring: oklch(0.708 0 0);

Fonts

--default-font-family:
  "Geist", sans-serif --default-mono-font-family: "Geist Mono", monospace;

Using Theme Variables in Components

// Use Tailwind color utilities
<div className="bg-primary text-primary-foreground">
  Primary button
</div>

<div className="dark:bg-card dark:text-card-foreground">
  Dark mode specific
</div>

// Or direct CSS variable access
<div style={{ backgroundColor: 'var(--primary)' }}>
  Direct variable
</div>

Animation Infrastructure

Tailwind Animations (Built-in)

Available through tw-animate-css plugin:

  • animate-in / animate-out - Fade, zoom, slide animations
  • fade-in-0 / fade-out-0 - Opacity animations
  • zoom-in-95 / zoom-out-95 - Scale animations
  • slide-in-from-* - Directional slide animations (top-2, left-2, right-2, bottom-2)

Custom Animations Defined in globals.css

Marquee Animation

@keyframes marquee {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(200%);
  }
}
.animate-marquee {
  animation: marquee 2s linear infinite;
}

Used in: LoadingBar.tsx, progress indicators

Shimmer Animation (for skeletons)

@keyframes shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}

Used in: skeleton.tsx for loading state

Settings Highlight (light mode)

@keyframes settings-highlight {
  0% {
    background-color: oklch(0.85 0 0);
  }
  100% {
    background-color: transparent;
  }
}
.settings-highlight {
  animation: settings-highlight 1.5s ease-out;
}

Settings Highlight (dark mode)

@keyframes settings-highlight-dark {
  0% {
    background-color: oklch(0.35 0 0);
  }
  100% {
    background-color: transparent;
  }
}

Used in: Settings UI when items are newly highlighted

Framer Motion

  • Installed: framer-motion: ^12.6.3
  • Use for complex animations, choreography, gesture animations
  • Not required for basic UI (Tailwind animations cover most cases)
  • Example: Can be used for smooth chat message entrance, complex transitions

Animation in UI Components

Dialog Animations

// Data attributes control state-based animations
<DialogOverlay className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0" />
<DialogPopup className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95" />

Tooltip Animations

// Tooltip fades in, zooms in from 95% scale
<TooltipContent className="data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95" />

Dropdown Animations

// Data attributes for animation states
data-state="open/closed"
data-side="top/bottom/left/right"

Prose/Typography Support

@tailwindcss/typography Plugin

  • Installed & Active: @tailwindcss/typography: ^0.5.16
  • CSS Plugin import: @plugin "@tailwindcss/typography"; in globals.css
  • Usage: Add prose class to container for markdown-like content

Prose Configuration (Chat-Ready)

// Applied in ChatMessage.tsx for markdown rendering
<div
  className="prose dark:prose-invert 
                prose-headings:mb-2 
                prose-p:my-1 
                prose-pre:my-0 
                max-w-none 
                break-words"
>
  {/* Markdown content renders here */}
</div>

Available prose modifiers:

  • prose - Base prose styling
  • dark:prose-invert - Inverted colors for dark mode
  • prose-headings:mb-2 - Heading margins
  • prose-p:my-1 - Paragraph margins
  • prose-pre:my-0 - Code block spacing
  • max-w-none - No width constraint (full container)
  • break-words - Break long words in chat

Code Highlighting in Chat

// CodeHighlight.tsx uses shiki with 'not-prose' to avoid double styling
<div className="shiki not-prose relative [&_pre]:overflow-auto">
  {/* Syntax-highlighted code */}
</div>

Theme Context & Dark Mode

ThemeContext.tsx Features

  • Theme Options: "system" (default) | "light" | "dark"
  • Persistence: Saves to localStorage
  • System Detection: Watches prefers-color-scheme media query
  • DOM Application: Adds .dark or .light class to <html> element

Usage

import { useTheme } from "@/contexts/ThemeContext";

function MyComponent() {
  const { theme, isDarkMode, setTheme } = useTheme();

  return (
    <>
      <p>Current theme: {theme}</p>
      <p>Dark mode active: {isDarkMode}</p>
      <button onClick={() => setTheme("dark")}>Dark</button>
      <button onClick={() => setTheme("light")}>Light</button>
      <button onClick={() => setTheme("system")}>System</button>
    </>
  );
}

How it works:

  • ThemeProvider wraps entire app (in root layout)
  • CSS variables automatically switch via .dark class selector
  • All shadcn components use CSS variables → automatic dark mode support
  • No component refactoring needed for theme support

Recommended Chat UI Composition Examples

Message Container

import { Card, CardContent } from "@/components/ui/card";

export function ChatMessage({ role, content }) {
  return (
    <Card
      className={cn(
        role === "user" ? "ml-auto bg-primary" : "bg-card",
        "max-w-2xl",
      )}
    >
      <CardContent
        className={cn(
          role === "user" ? "text-primary-foreground" : "text-card-foreground",
          "prose dark:prose-invert",
        )}
      >
        {content}
      </CardContent>
    </Card>
  );
}

Chat Input with Actions

import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
  Tooltip,
  TooltipTrigger,
  TooltipContent,
} from "@/components/ui/tooltip";

export function ChatInput() {
  return (
    <div className="flex gap-2 items-end">
      <Input placeholder="Type message..." className="flex-1" />
      <Tooltip>
        <TooltipTrigger asChild>
          <Button size="icon">Send</Button>
        </TooltipTrigger>
        <TooltipContent>Send message (Ctrl+Enter)</TooltipContent>
      </Tooltip>
    </div>
  );
}

Streaming Response with Skeleton

import { Skeleton } from "@/components/ui/skeleton";
import { motion } from "framer-motion";

export function StreamingMessage({ isStreaming }) {
  return isStreaming ? (
    <motion.div
      initial={{ opacity: 0, y: 8 }}
      animate={{ opacity: 1, y: 0 }}
      className="bg-card rounded-lg p-4 space-y-2"
    >
      <Skeleton className="h-4 w-full" />
      <Skeleton className="h-4 w-3/4" />
    </motion.div>
  ) : null;
}

Key Design Tokens Summary

TokenLightDarkUse Case
bg-primaryoklch(0.205) - Darkoklch(0.985) - LightPrimary buttons, active states
bg-cardoklch(1) - Whiteoklch(0.145) - DarkMessage containers, cards
bg-backgroundoklch(1) - Whiteoklch(0.145) - DarkPage background
text-foregroundoklch(0.145) - Darkoklch(0.985) - LightBody text
borderoklch(0.922) - Light grayoklch(0.269) - Dark grayDividers, borders
bg-destructiveoklch(0.577 0.245 27.325)oklch(0.396 0.141 25.723)Error/delete actions
proseMarkdown stylingInverted markdownMessage content

Configuration Files Location

  • CSS Variables: src/styles/globals.css (lines 90-219)
  • Theme Context: src/contexts/ThemeContext.tsx
  • UI Components: src/components/ui/*.tsx
  • Chat Components: src/components/chat/*.tsx
  • Tailwind (via Vite): vite.renderer.config.mts (uses @tailwindcss/vite plugin)

Ready-to-Use Patterns

Error Messages

<Alert className="bg-destructive/10 border-destructive/30">
  <AlertDescription className="text-destructive">
    Error message here
  </AlertDescription>
</Alert>

Loading States

<Skeleton className="h-12 w-full rounded-md animate-shimmer" />

Disabled States

<Button disabled className="opacity-50 cursor-not-allowed">
  Action
</Button>

Responsive Layout

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  {/* items */}
</div>

This infrastructure is production-ready and has been used throughout the app for consistent, accessible, and themeable UI.

What's inside

5 major sections: component list, CSS variables, animations, theme context, and chat UI examples with code snippets.

Change this for your project

  • Replace src/styles/globals.css with your own CSS file path
  • Replace src/contexts/ThemeContext.tsx with your own context file path
  • Replace src/components/chat/ with your own chat components directory
  • Replace vite.renderer.config.mts with your own Vite config file name

Where it goes

Save in docs/ or the repository root. Gives agents and new contributors a map of the codebase.

Worth borrowing

  • Using OKLch color space for theme variables enables smooth light/dark mode switching without component refactoring
  • Data attribute animations (data-open:, data-closed:) on shadcn/ui components keep animation logic in markup
  • Combining prose with not-prose on code blocks prevents double styling when rendering markdown

Related Documents