Skip to main content
Urbicon UI

ChatMessageexperimental

Renders one message and its ordered parts — markdown text via StreamingMarkdown, reasoning, tool-call status, attachment chips, and a deduplicated citation footer — with a hover-revealed copy/regenerate bar and an error/aborted alert. bubble tints and aligns per role; plain is a document-like full-width column.

One message rendered on its own. Flip the layout between the tinted bubble and the document-like plain column, change the role to see the per-role tint and alignment, and hover the message to reveal the copy / regenerate bar. For the whole conversation in motion, open the live playground.

Here is the plan. The renderer parses the growing string into a component tree — no {@html} anywhere — so settled blocks stay cached and only the tail re-renders.

  1. Text parts flow through StreamingMarkdown

  2. Every link is checked against the URL policy

  3. [1] markers resolve to citation chips

Layout
Density
Role
Loading...
Loading syntax highlighting...

01 Examples

An agentic message

Reasoning, a tool call, answer text, and two sources — rendered in part order. The reasoning collapses into a 'Thought for 2s' disclosure, the tool call shows its settled state, and the sources dedupe into the citation footer while their [1] / [2] markers become inline chips.
Assistant

The user wants sources. Look up the attention paper and the scaling-laws work, then cite both inline.

Input
json
{
  "query": "transformer attention scaling laws"
}
Output
json
{
  "hits": 2
}

The Transformer replaced recurrence with self-attention

, and later work showed its performance scales predictably with compute
.

Loading...
Loading syntax highlighting...

Custom tool-call renderer

partRenderers replaces the built-in rendering for a single part type — keyed by the part's type — without touching the rest of the dispatch. Here a compact status pill stands in for the default ToolCallCard; the snippet receives the fully-typed tool-call part.
Assistant
get_weather → complete

It's 7 °C and overcast in Berlin right now.

Loading...
Loading syntax highlighting...

Error state with retry

A message with status='error' keeps whatever text streamed in and appends an Alert. Passing onRetry renders the Retry button; the same handler drives aborted messages too.
Assistant

Let me pull the latest figures for you

Retry pressed 0×

Loading...
Loading syntax highlighting...

02 Part dispatch

A message is an ordered list of parts. ChatMessage walks them in order and picks a renderer per type — this is what lets a single component present a plain answer and a full agentic transcript alike.

  • text → rendered through StreamingMarkdown (never {@html}; every link is URL-policy checked).
  • reasoning → a collapsed ReasoningDisclosure with a "Thought for Xs" label.
  • tool-call → a ToolCallCard reflecting its pending / running / complete / error state.
  • attachment → a policy-checked chip; the URL is only ever a download link, never inline media.
  • source → collected out of the flow into the deduplicated citation footer (and feeds the [n] markers).

Override any part type except source via partRenderers, and swap the avatar, action bar or metadata row through their respective snippets. The component never mutates the message it is handed.

03 Accessibility

Labelled actions

The copy and regenerate buttons carry aria-labels (copyLabel, regenerateLabel) and are wrapped in tooltips. They live in a bar revealed on hover / focus-within, so keyboard users reach them by tabbing — the reveal is presentational, not a focus trap.

Copy feedback

A successful copy is announced through a visually hidden role="status" region (the copiedLabel text), so screen-reader users hear the confirmation without a visible toast.

Error & aborted alerts

status: 'error' and 'aborted' render through the Alert primitive, so the failure is exposed with the correct alert semantics rather than styled text alone.

Decorative avatar & time

The role avatar is decorative and hidden from assistive tech; the timestamp renders as a semantic <time datetime> element so the machine-readable instant travels with the visible label.

04 API Reference

23 props
23 props 1 required

No matching properties

No matching properties

05 Installation

Import

Loading...
Loading syntax highlighting...