Marker

Displays an inline status, system note, bordered row, or labeled separator in a conversation.

Switched to a new branch
Operating…
Thinking…
Conversation compacted
Explored 4 files

The Marker component displays inline conversation markers such as status updates, system notes, bordered rows, and labeled separators. In a conversation, always render it inside a Message. See In a Conversation.

Installation

import { Marker } from "@o/pipeline/experimental/components/chat/marker";

Usage

import { IconCheck } from "@o/pipeline/experimental/icons";
import { Marker } from "@o/pipeline/experimental/components/chat/marker";
<Marker.Root>
  <Marker.Icon>
    <IconCheck />
  </Marker.Icon>
  <Marker.Content>Explored 4 files</Marker.Content>
</Marker.Root>

Composition

Use the following composition to build a marker:

Marker.Root
├── Marker.Icon
└── Marker.Content

In a Conversation

A marker in a conversation is a row in the transcript, so render it inside Message.Root and Message.Content like any other message. Message keeps the transcript’s rhythm: it reserves the band below each row, so a marker rendered on its own collapses against the message under it. It also lines the marker up with the message column instead of letting it draw its own layout.

Leave out Message.Avatar for a marker with no sender, such as a date divider or a system note, so it starts at the row’s edge. For a status about a sender, such as a typing indicator, add their avatar and put the marker in Message.Header, where their name would go.

<Message.Root>
  <Message.Content>
    <Marker.Root variant="separator">
      <Marker.Content>Today</Marker.Content>
    </Marker.Root>
  </Message.Content>
</Message.Root>

A marker inside a message’s own content, such as a fallback for a block that can’t render, is already inside a Message and needs no extra wrapper.

Features

  • Inline marker, bordered row, and labeled separator variants
  • Decorative icon slot that is hidden from assistive tech
  • Polymorphic root via render for link and button markers
  • Built-in shimmer prop for streaming status text
  • Customizable styling through the className prop on every part

Variants

Use variant to switch between an inline marker, bordered row, and labeled separator.

A default marker for inline notes.
A separator marker
A border marker for row boundaries.
VariantDescription
defaultAn inline marker for status, notes, and actions.
borderA default marker with a bottom border under the row.
separatorA centered label with divider lines on each side.

Status

Set role="status" and include a Spinner for streaming or in-progress markers so updates are announced.

Compacting conversation
Running tests

Shimmer

Set shimmer on Marker.Content for a compositor-only animated streaming-text effect. Firefox and users who prefer reduced motion see static text instead.

Tune the effect with --shimmer-angle, --shimmer-color, --shimmer-duration, and --shimmer-spread.

The shimmer clones its children into an inert overlay. Pass plain text or presentational content, not stateful components, because children mount twice, once visibly and once in the inert overlay, so effects would run twice. Avoid id attributes inside shimmer content because the clone would duplicate them.

Thinking…
Reading 4 files

Separator

Use the separator variant for labeled dividers, such as dates or section breaks, in a conversation.

Today
Worked for 42s
Conversation compacted

Border

Use the border variant for status rows that should keep the default marker alignment while separating the next row.

Switched to release-candidate
Reviewed 8 related files
Opened implementation notes

With Icon

Use Marker.Icon to render an icon alongside the content. Use flex-col to stack the icon above the content.

Switched to a new branch
Explored 4 files
Syncing completed

Turn a marker into a link or button with the render prop on Marker.Root.

View the pull request

Accessibility

Marker.Root is presentational by default. The correct semantics depend on how you use it, so choose the role based on intent rather than relying on a single default.

Status and Progress

For streaming or progress markers such as “Thinking…” or a running tool, set role="status" so assistive tech announces the update as it appears. Marker.Root forwards role to the underlying element.

<Marker.Root role="status">
  <Marker.Icon>
    <Spinner />
  </Marker.Icon>
  <Marker.Content>Compacting conversation</Marker.Content>
</Marker.Root>

Labeled Separators

A separator that carries text, such as a date or a section label, needs no role. The divider lines are decorative CSS pseudo-elements, and the text is announced as ordinary content.

<Marker.Root variant="separator">
  <Marker.Content>Today</Marker.Content>
</Marker.Root>

Note

Do not add role="separator" to a labeled divider. A separator takes its accessible name from aria-label, not from its text, and its contents are treated as presentational, so the visible label would not be announced. Reserve role="separator" for a divider with no meaningful text.

Bordered Markers

A bordered marker keeps the same semantics as the default marker. The bottom border is decorative, so choose role="status", render, or no role based on the marker’s purpose.

<Marker.Root variant="border">
  <Marker.Icon>
    <IconFileText />
  </Marker.Icon>
  <Marker.Content>Opened implementation notes</Marker.Content>
</Marker.Root>

Decorative Icons

Marker.Icon is decorative and hidden from assistive tech with aria-hidden, so the adjacent Marker.Content carries the meaning. For an icon-only marker, provide an aria-label or visible text so it is not announced as empty.

<Marker.Root aria-label="Synced">
  <Marker.Icon>
    <IconCheck />
  </Marker.Icon>
</Marker.Root>

Interactive Markers

When a marker links or triggers an action, render it as a real <button> or <a> with the render prop so it is focusable and exposes the correct role. The accessible name comes from the marker text.

<Marker.Root render={<a href="/files" />}>
  <Marker.Icon>
    <IconFileText />
  </Marker.Icon>
  <Marker.Content>Explored 4 files</Marker.Content>
</Marker.Root>

API Reference

Marker.Root

The root marker element.

PropTypeDefaultDescription
variant"default" | "border" | "separator""default"The marker layout.
renderReactElement | function-Render as a different element, such as a link.
classNamestring-Additional classes to apply to the root element.

Marker.Icon

A decorative icon slot. Hidden from assistive tech with aria-hidden.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the icon slot.

Marker.Content

The marker text content.

PropTypeDefaultDescription
shimmerbooleanfalseShow a compositor-only streaming-text shimmer.
classNamestring-Additional classes to apply to the content slot.