Chat Dock Section

Sidebar section that hosts a compact, scrollable chat thread alongside a spatial workspace — slotted into a dock or rail to keep an AI assistant in view. Install Chat Dock Section from the VLLNT UI registry with the shadcn CLI.

Report a bug

Sidebar section that hosts a compact, scrollable chat thread alongside a spatial workspace — slotted into a dock or rail to keep an AI assistant in view. Part of the ai family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

Add Chat Dock Section to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/chat-dock-section.json

Source

import { ArrowUpRight, MessageSquareText } from "lucide-react"; import type { ReactNode } from "react"; import { cn } from "../../lib/utils"; import { Button } from "../button/button"; export type ChatDockMessage = { body: ReactNode; id: string; speaker: ReactNode; }; export type ChatDockSectionProps = React.ComponentPropsWithoutRef<"section"> & { composerPlaceholder?: string; contextLabel?: ReactNode; messages: ChatDockMessage[]; title?: ReactNode; }; const ChatDockSection = ({ className, composerPlaceholder = "Ask about runs, errors, or pending work…", contextLabel, messages, ref, title = "Assistant", ...props }: ChatDockSectionProps & { ref?: React.Ref<HTMLElement> }) => ( <section className={cn( "flex flex-col gap-4 rounded-2xl border border-border/70 bg-background/75 p-4 shadow-[0_10px_35px_oklch(var(--foreground)/0.06)] backdrop-blur-xl", className, )} ref={ref} {...props} > <div className="flex items-start justify-between gap-3"> <div className="space-y-2"> <div className="flex items-center gap-2 text-sm font-medium text-foreground"> <MessageSquareText className="size-4 text-primary" /> {title} </div> {contextLabel ? ( <div className="text-xs uppercase tracking-[0.24em] text-muted-foreground"> {contextLabel} </div> ) : null} </div> <Button size="sm" type="button" variant="ghost"> Open thread <ArrowUpRight className="size-4" /> </Button> </div> <div className="space-y-3"> {messages.map((message) => ( <div className="rounded-xl border border-border/60 bg-background/85 px-3 py-2" key={message.id} > <div className="text-[11px] font-medium uppercase tracking-[0.18em] text-muted-foreground"> {message.speaker} </div> <div className="mt-2 text-sm leading-6 text-foreground"> {message.body} </div> </div> ))} </div> <div className="rounded-xl border border-dashed border-border/80 bg-background/70 p-3 text-sm text-muted-foreground"> {composerPlaceholder} </div> </section> ); ChatDockSection.displayName = "ChatDockSection"; export { ChatDockSection };

Stories

Explore every variant and state in the interactive Storybook:

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Dependencies

  • @vllnt/ui@^0.3.0