Skip to content
Sign in
Chat layoutsSpotlight chatMenu

Spotlight chatPro

A command bar that answers: one line that grows into suggested actions as you type, then into an answer panel that follows the reply as it streams.

ProA studio workspace with the bar open: two questions asked and answered on their own, then yours.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/spotlight-chat

Usage

tsx
import { SpotlightChat } from "@/components/ui/chatcn/pro/spotlight-chat"

<SpotlightChat
  messages={chat.chatcnMessages}
  status={chat.status}
  onSend={(text) => chat.sendMessage({ text })}
  onStop={chat.stop}
  actions={[{ id: "brief", label: "Summarize this week's feedback" }]}
  followUps={["Which of these change the budget?"]}
  context="Halden Studio workspace"
/>

The bar has three sizes and one surface. Closed it is a single line with its shortcut. Typing opens a list: the first row asks exactly what you typed, the rest are your actions filtered by label and keywords. Asking grows it again into the answer, and the panel height follows the reply token by token, so it never jumps when a tool call or a source list arrives. Escape steps back one level at a time and the footer always names what it will do next: stop, collapse, clear, close. Collapsing keeps the thread behind a Show answer button, so a follow up starts where you left off. Actions with onSelect run instead of asking. onContinue and onNewChat add their buttons to the answer footer.

Examples

States

ProClosed with its shortcut, typing with matches, thinking, an error, an answer kept behind the bar, disabled.

Props

PropTypeNotes
messagesChatcnMessage[]The thread. Pass useChatcnChat().chatcnMessages
status"ready" | "submitted" | "streaming" | "error"Same as AI SDK useChat
errorReactNodeShown with a retry. Say how to fix it
onSend, onStop, onRetry(text) => void, () => void, () => voidWire to your chat
actions{ id, label, prompt?, icon?, hint?, keywords?, onSelect? }[]Suggested rows
followUpsstring[]Offered under the finished answer, arrow keys reach them
contextReactNodeWhat answers come from, at the start of the footer
onContinue, onNewChat() => voidContinue in chat and New question buttons
value, defaultValue, onValueChangestringThe input, controlled or not
open, defaultOpen, onOpenChangebooleanClosed shows the one line trigger
expanded, defaultExpanded, onExpandedChangebooleanThe answer panel is showing
hotkey, hotkeyTargetstring | null, RefObjectDefault mod+k; scope it to one pane
triggerbooleanRender the closed line. Default true
maxAnswerHeightstringBefore the answer scrolls. Default min(24rem, 56dvh)
disabledboolean
labelsPartial<SpotlightChatLabels>Every string, for translation

Keyboard

KeyAction
Cmd K or Ctrl KOpen or close the bar
Up and DownMove through actions or follow ups; Down on the bar shows the kept answer
EnterAsk, or run the highlighted row
EscapeStop, then collapse, then clear, then close: one level per press

Accessibility

  • The input is a combobox; rows are options reached with aria-activedescendant, so focus never leaves the input.
  • The bar is a labelled region and the shortcut is announced with aria-keyshortcuts.
  • Closing hands focus back to the trigger line.
  • The panel content is inert while it is collapsing, so hidden rows are never reachable.

Motion

The panel opens in 280 ms and closes in 210 ms on the kit's ease out, following the content height as it streams; its contents fade in 150 ms. Reduced motion snaps the height and keeps the fade.