Chat
Chat is a family of composable primitives for building AI and human chat experiences. Combine ChatLayout, ChatMessageList, ChatMessage, bubbles, system messages, tool calls, tokenized text, and ChatComposer to assemble complete conversations without reimplementing sender-aware layout, density, scrolling, or composer behavior.
Usage
Chat is a family of composable primitives for building AI and human chat experiences. Combine ChatLayout, ChatMessageList, ChatMessage, bubbles, system messages, tool calls, tokenized text, and ChatComposer to assemble complete conversations without reimplementing sender-aware layout, density, scrolling, or composer behavior.
- Compose messages using MessageList > Message > Bubble for consistent sender-aware styling and density.
- Set the density prop to control spacing globally: compact for sidebars, balanced for most views, spacious for long-form reading. Individual messages can override.
- Use gap when top-level rows are independent (for example, LLM tool events or streamed blocks) and list spacing needs to be tuned separately from density.
- Use the group prop on bubbles (first, middle, last) when a single sender sends multiple consecutive messages; it tightens corner radius to visually connect them.
- Use ChatSystemMessage with variant="divider" for date separators and default for inline status notices like joins, leaves, or topic changes.
- Put name on the first bubble and metadata on the last bubble in a message so they align with the bubble's inline padding.
- Wrap custom in-message content (cards, attachments, citations) in a ghost bubble so it aligns with the bubble text column; add width="100%" when it should span the full message column instead of the default bubble width cap.
- Provide an emptyState prop so new users see a clear prompt to start a conversation instead of a blank screen.
- Use the ghost bubble variant for AI-style responses that show rich content like code blocks or markdown without a visible boundary.
- Don't use ChatSystemMessage for sender content; it has no avatar, alignment, or bubble. Use ChatMessage with a sender role instead.
- Don't put long or multi-line content in a system message; keep it to a single short sentence. If you need more, use a bubble or a card.
- Don't nest ChatMessage inside another ChatMessage; each message is a standalone article element with its own sender context.
- Don't apply a fixed height directly on the message list; wrap it in a sized container and let the list fill with flex: 1.
- Don't mix filled and ghost bubble variants within the same sender's messages; pick one style per side and use it consistently.
- Don't place metadata or names on both the bubble and the message wrapper; pick one based on whether the content has a bubble boundary.
Anatomy
Scrollable region for messages. Renders children (typically ChatMessageList) in a flex column that pushes content to the bottom when the list is short.
Sticky or fixed container at the bottom with a backdrop-blur layer. Houses the scroll button and composer.
Appears when the user scrolls up or new messages arrive. Defaults to ChatLayoutScrollButton; pass null to hide or a custom element to override.
The input area for sending messages, typically ChatComposer. Docked at the bottom inside the frosted glass layer.
Centered placeholder shown when no messages exist. Use EmptyState for a consistent look.
A sender avatar rendered beside the message. Typically Avatar with size="md". Hidden for system messages.
Sender name above the message body. Place on the bubble when using bubbles, or on the message wrapper for raw content.
The message body: one or more ChatMessageBubble elements, or any free-form ReactNode like images or tool calls. Wrap non-bubble content in a ghost bubble to align it with the bubble text column.
Timestamp, delivery status, and footer actions below the message. Place on the last bubble or on the message wrapper.
Theming
Targets
astryx-chat-layoutVisual props: density
astryx-chat-composerVisual props: density
astryx-chat-composer-inputastryx-chat-composer-drawerVisual props: collapsed
astryx-chat-messageVisual props: sender, density
astryx-chat-message-bubbleVisual props: sender, variant, density
astryx-chat-message-listVisual props: density
astryx-chat-system-messageVisual props: variant
astryx-chat-message-metadataastryx-chat-send-buttonastryx-chat-dictation-buttonastryx-chat-layout-scroll-buttonastryx-chat-tokenized-textastryx-chat-tool-callsastryx-trigger-menuVariables
--_chat-composer-radiusBorder radius of the composer body. Inner elements derive their radius concentrically.
Default: var(--radius-chat)
--_chat-composer-paddingPadding of the composer body. Used in the concentric radius calculation.
Default: var(--spacing-3)
--_button-radiusConcentric button radius inside the composer.
Default: max(var(--radius-element), calc(var(--_chat-composer-radius) - var(--_chat-composer-padding)))
Formula: max(var(--radius-element), calc(var(--_chat-composer-radius) - var(--_chat-composer-padding)))
Derived properties
borderRadiusUses --_chat-composer-radius.
paddingUses --_chat-composer-padding.