Overview

Unstyled, accessible building blocks for AI chat interfaces.

Primitives are the foundation of assistant-ui. They are unstyled, accessible React components that handle all the wiring for AI chat, including state management, keyboard shortcuts, auto-scrolling, streaming, and tool calls, so you can focus entirely on your UI.

Why Primitives?

Every assistant-ui Component is built from primitives. When you install a component like Thread, you get a pre-styled composition of primitives with default styling and behavior included.

But when you need a UI that doesn't fit the defaults, such as a floating composer, a custom message layout, or an inline editing experience, you reach for the primitives directly.

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

Start with the Composer primitive to see how primitives work in practice, or jump to the API Reference for full prop details.