Unstyled, accessible building blocks for AI chat interfaces — Thread, Composer, Message, and more, ready to compose with assistant-ui.
Primitives are the unstyled layer of assistant-ui: accessible React components that handle all the wiring of AI chat, including state management, keyboard shortcuts, auto-scrolling, streaming, and tool calls, and leave every visual decision to you.
Primitives or elements?
assistant-ui ships two layers:
- Elements are styled, installable components built from primitives. Each element's page shows a live demo, its install command, and both ways to use it: wired to a runtime, or driven by plain props. If you want ready-made UI, or anything else element-related, the element catalog is the place to look; this section never duplicates it.
- Primitives (this section) are what elements are made of. Reach for them when the UI you need doesn't exist as an element, such as a floating composer, a custom message layout, or an inline editing experience.
import { ComposerPrimitive } from "@assistant-ui/react";
<ComposerPrimitive.Root>
<ComposerPrimitive.Input placeholder="Ask anything..." />
<ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
</ComposerPrimitive.Root>This renders an unstyled <form> with a <textarea> and a <button>. No styles, no opinions, but it already handles submit-on-enter, focus management, empty-state disabling, and streaming state.
How they work
Every primitive follows the same pattern inspired by Radix UI:
Primitive.Root: container that provides context to child partsPrimitive.PartName: individual elements (input, button, text, etc.)asChild: merge primitive behavior onto your own element instead of rendering a wrapperAuiIf: conditional rendering based on state
Primitives read from the nearest runtime context. Place them inside an AssistantRuntimeProvider and they work without prop drilling or manual state wiring.
Available primitives
Text input, send button, attachments, and dictation. The interface for composing new messages or editing existing ones.
ThreadThe scrollable message container with auto-scroll, empty states, and message rendering.
MessageIndividual message rendering with role-based content, parts, and metadata.
ActionBarCopy, reload, edit, and other message actions.
BranchPickerNavigate between message branches (alternative responses).
ThreadListMulti-thread management: list, create, switch, and archive threads.
AssistantModalFloating chat popover built on Radix UI Popover.
AttachmentFile and image attachment rendering.
SuggestionSuggested prompts and quick actions.
SelectionToolbarFloating toolbar for text selection actions like quoting.
ErrorError display with accessible alert role and automatic error text.
ChainOfThoughtCollapsible reasoning accordion for thinking steps and tool calls.
MessagePartPrimitive (for rendering individual text, image, and streaming parts) is documented within the Message primitive page.
Related primitive references
Additional primitive references:
- MessagePartPrimitive
- ThreadListItemPrimitive
- ThreadListItemMorePrimitive
- ActionBarMorePrimitive
- AuiIf
Common mistakes
- Forgetting to wrap primitives with runtime context (
AssistantRuntimeProvider+ runtime hook) - Mixing deprecated props with current APIs (
submitOnEnter,autoSend, legacySuggestion) - Mounting primitives in the wrong context (
ActionBarPrimitive/BranchPickerPrimitiveoutsideMessagePrimitive.Root) - Using unstable props unintentionally (
unstable_*APIs)
Next steps
Browse the element catalog if a ready-made component covers your case. Otherwise start with the Composer primitive to see how primitives work in practice, or jump to the API Reference for full prop details.