Guide for assistant-ui UI primitives - ThreadPrimitive, ComposerPrimitive, MessagePrimitive. Use when customizing chat UI components.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add compozy/compozy --skill assistant-ui-primitives --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Assistant Ui Primitives?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/compozy-assistant-ui-primitives)More formats (shields.io, HTML) on the badges page.
---
name: assistant-ui-primitives
description: Guide for assistant-ui UI primitives - ThreadPrimitive, ComposerPrimitive, MessagePrimitive. Use when customizing chat UI components.
version: 0.0.1
license: MIT
---
# assistant-ui Primitives
**Always consult [assistant-ui.com/llms.txt](https://assistant-ui.com/llms.txt) for latest API.**
Composable, unstyled components following Radix UI patterns.
## References
- [./references/thread.md](./references/thread.md) -- ThreadPrimitive deep dive
- [./references/composer.md](./references/composer.md) -- ComposerPrimitive deep dive
- [./references/message.md](./references/message.md) -- MessagePrimitive deep dive
- [./references/action-bar.md](./references/action-bar.md) -- ActionBarPrimitive deep dive
## Import
```tsx
import {
AuiIf,
ThreadPrimitive,
ComposerPrimitive,
MessagePrimitive,
ActionBarPrimitive,
BranchPickerPrimitive,
AttachmentPrimitive,
ThreadListPrimitive,
ThreadListItemPrimitive,
} from "@assistant-ui/react";
```
## Primitive Parts
| Primitive | Key Parts |
|-----------|-----------|
| `ThreadPrimitive` | `.Root`, `.Viewport`, `.Messages`, `.Empty`, `.ScrollToBottom` |
| `ComposerPrimitive` | `.Root`, `.Input`, `.Send`, `.Cancel`, `.Attachments` |
| `MessagePrimitive` | `.Root`, `.Parts`/`.Content`, `.If`, `.Error` |
| `ActionBarPrimitive` | `.Copy`, `.Edit`, `.Reload`, `.Speak`, `.FeedbackPositive`, `.FeedbackNegative`, `.ExportMarkdown` |
| `BranchPickerPrimitive` | `.Previous`, `.Next`, `.Number`, `.Count` |
## Custom Thread Example
```tsx
function CustomThread() {
return (
<ThreadPrimitive.Root className="flex flex-col h-full">
<ThreadPrimitive.Empty>
<div className="flex-1 flex items-center justify-center">
Start a conversation
</div>
</ThreadPrimitive.Empty>
<ThreadPrimitive.Viewport className="flex-1 overflow-y-auto p-4">
<ThreadPrimitive.Messages components={{
UserMessage: CustomUserMessage,
AssistantMessage: CustomAssistantMessage,
}} />
</ThreadPrimitive.Viewport>
<ComposerPrimitive.Root className="border-t p-4 flex gap-2">
<ComposerPrimitive.Input className="flex-1 rounded-lg border px-4 py-2" />
<ComposerPrimitive.Send className="bg-blue-500 text-white px-4 py-2 rounded-lg">
Send
</ComposerPrimitive.Send>
</ComposerPrimitive.Root>
</ThreadPrimitive.Root>
);
}
```
## Conditional Rendering
Prefer `AuiIf` for new code. Primitive `.If` components still exist but are deprecated.
```tsx
<AuiIf condition={({ message }) => message.role === "user"}>
User only
</AuiIf>
<AuiIf condition={({ thread }) => thread.isRunning}>
Generating...
</AuiIf>
<AuiIf condition={({ message }) => message.branchCount > 1}>
Has edit history
</AuiIf>
<AuiIf condition={({ thread }) => thread.isRunning}>
<ComposerPrimitive.Cancel>Stop</ComposerPrimitive.Cancel>
</AuiIf>
<AuiIf condition={({ thread }) => thread.isEmpty}>No messages</AuiIf>
```
## Content Parts
```tsx
<MessagePrimitive.Content components={{
Text: ({ part }) => <p>{part.text}</p>,
Image: ({ part }) => <img src={part.image} alt="" />,
ToolCall: ({ part }) => <div>Tool: {part.toolName}</div>,
Reasoning: ({ part }) => <details><summary>Thinking</summary>{part.text}</details>,
}} />
```
## Branch Picker
```tsx
<MessagePrimitive.If hasBranches>
<BranchPickerPrimitive.Root className="flex items-center gap-1">
<BranchPickerPrimitive.Previous>←</BranchPickerPrimitive.Previous>
<span><BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count /></span>
<BranchPickerPrimitive.Next>→</BranchPickerPrimitive.Next>
</BranchPickerPrimitive.Root>
</MessagePrimitive.If>
```
## Common Gotchas
**Primitives not rendering**
- Wrap in `AssistantRuntimeProvider`
- Ensure parent primitive provides context
**Styles not applying**
- Primitives are unstyled by default
- Add `className` and style with your app's Tailwind/CSS system
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!