Message
Single chat-message row scoped to one speaker (user / assistant / system / tool). Headless content slot — pair with Markdown, CodeBlock, or ToolCall children.
User → assistant turn
Tabs primitive — Radix handles arrow-key navigation, focus management, and the roving-tabindex pattern for you.Composed assistant turn — markdown + reasoning + actions
Yes — pair Tabs with a labelled TabsList and one
TabsContent per panel. The trigger value selects the panel
with the same value.
<Tabs defaultValue="overview" aria-label="Settings">
<TabsList>…</TabsList>
<TabsContent value="overview">…</TabsContent>
</Tabs>
Installation
pnpm dlx @hex-core/cli add messageComposed assistant turn
Markdown + ToolCall inside one assistant message.
<Message role="assistant">
<Markdown>{response}</Markdown>
<ToolCall name="search" state="result" result={hits} />
</Message>Variant values
roleVisual treatment per speaker.| Value | Description |
|---|---|
user | Tinted secondary background — user turns. |
assistantdefault | Card background — model output. |
system | Muted, italic — system instructions. |
tool | Accent left-border — tool messages distinct from assistant text. |
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
rolerequired | "user" | "assistant" | "system" | "tool" | — | Speaker. Drives variant styling and the data-role attribute. |
childrenrequired | ReactNode | — | Message content. Strings, Markdown, CodeBlock, ToolCall, or any composition. |
className | string | — | Additional CSS classes merged onto the row. |
AI Guidance
When to use
Wrap every conversation turn — user, assistant, system, or tool. Pair with MessageList for the scrolling viewport. Compose Markdown, CodeBlock, and ToolCall as children for rich assistant turns.
When not to use
Don't use for non-conversational text (use Card or plain elements). Don't put streaming logic here — the consumer drives state, Message just renders.
Common mistakes
- Adding streaming/fetch logic inside Message — keep it pure
- Using `role="tool"` for assistant text that mentions a tool — `tool` is for the actual tool turn
- Hard-coding markdown rendering inside Message — pass <Markdown>{...}</Markdown> as a child instead
Accessibility
Renders as a div with `data-role`. For screen-reader chat semantics, wrap MessageList in `role="log"` and consider `aria-live="polite"` on the streaming container.
Related components
Token budget: 220
Verified against @hex-core/components@1.12.0