Overview

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 parts
  • Primitive.PartName: individual elements (input, button, text, etc.)
  • asChild: merge primitive behavior onto your own element instead of rendering a wrapper
  • AuiIf: 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

MessagePartPrimitive (for rendering individual text, image, and streaming parts) is documented within the Message primitive page.

Additional primitive references:

Common mistakes

  • Forgetting to wrap primitives with runtime context (AssistantRuntimeProvider + runtime hook)
  • Mixing deprecated props with current APIs (submitOnEnter, autoSend, legacy Suggestion)
  • Mounting primitives in the wrong context (ActionBarPrimitive / BranchPickerPrimitive outside MessagePrimitive.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.