Getting Started
State-aware components for assistant-ui that eliminate chat UI boilerplate.
What are Chords?
A chord is a pre-composed component that reads runtime state and makes rendering decisions for you. You don't think about conditionals or status checks — the chord handles the wiring, you own the UI.
- Major Chord — Reads runtime state, makes multi-branch rendering decisions (e.g.
ComposerActionStatusswitches send/cancel/disabled based on thread state) - Minor Chord — Composes 2+ primitives into a pattern every app rebuilds (e.g.
ScrollToBottomwraps the primitive + icon positioning)
Each chord replaces 20-60 lines of manual wiring with a single, configurable component — while giving you full control over styling and behavior.
Why?
Building a chat UI with assistant-ui primitives gives you maximum flexibility, but common patterns require a lot of boilerplate:
- Toggling Send/Cancel buttons based on thread state
- Showing copy-with-feedback buttons on messages
- Configuring action bars with copy, reload, edit actions
- Rendering suggestion chips on empty threads
- Managing scroll-to-bottom visibility
Chords handle all of this for you, while keeping the same composability you're used to.
Quick Example
import { MessageActionBar } from "@assistant-ui/chords";
const AssistantMessage = () => (
<MessagePrimitive.Root>
<MessagePrimitive.Content />
<MessageActionBar actions={["copy", "reload"]} />
</MessagePrimitive.Root>
);const AssistantMessage = () => (
<MessagePrimitive.Root>
<MessagePrimitive.Content />
<ActionBarPrimitive.Root
hideWhenRunning
autohide="not-last"
autohideFloat="single-branch"
>
<ActionBarPrimitive.Copy asChild>
<button>
{/* need conditional icon toggle logic */}
<CopyIcon />
</button>
</ActionBarPrimitive.Copy>
<ActionBarPrimitive.Reload asChild>
<button>
<ReloadIcon />
</button>
</ActionBarPrimitive.Reload>
</ActionBarPrimitive.Root>
</MessagePrimitive.Root>
);Design Principles
- Zero config works — drop in with no props, get a working component
- Full override —
classNamereplaces defaults,renderVisualswaps icons — no fighting specificity - No lock-in — mix chords with raw primitives freely in the same tree
- Lightweight — minimal dependencies, no design system opinions
Next Steps
- Installation — add Chords to your project
- Major Chords — state-aware components with multi-branch logic
- Minor Chords — common primitive compositions