Components

Marker

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

Source code

Click to see the source code for this component on GitHub. Feel free to copy it and adjust it for your own use.

Installation

Usage

Switched to a new branch
Thinking...
Conversation compacted
Explored 4 files

Anatomy

vue

Marker Anatomy.vue

<template>
  <UiMarker>
    <UiMarkerIcon />
    <UiMarkerContent />
  </UiMarker>
</template>

Features

  • Inline marker, bordered row, and labeled separator variants
  • Decorative icon slot that is hidden from assistive tech
  • Polymorphic root via as or as-child for link and button markers
  • Pairs with the shimmer utility for streaming status text
  • Every part renders through Primitive, so as / as-child and Vue class overrides work on any part

Examples

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 loading icon for streaming or in-progress markers so updates are announced.

Compacting conversation
Running tests

Shimmer

Add the shimmer utility class to UiMarkerContent for an animated streaming-text effect.

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 UiMarkerIcon 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 as-child prop on UiMarker.

View the pull request

Accessibility

Marker 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. UiMarker forwards role to the underlying element.

<template>
  <UiMarker role="status">
    <UiMarkerIcon>
      <Icon name="lucide:loader-circle" class="animate-spin" />
    </UiMarkerIcon>
    <UiMarkerContent>Compacting conversation</UiMarkerContent>
  </UiMarker>
</template>

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.

<template>
  <UiMarker variant="separator">
    <UiMarkerContent>Today</UiMarkerContent>
  </UiMarker>
</template>

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", as-child, or no role based on the marker's purpose.

<template>
  <UiMarker variant="border">
    <UiMarkerIcon>
      <Icon name="lucide:file-text" />
    </UiMarkerIcon>
    <UiMarkerContent>Opened implementation notes</UiMarkerContent>
  </UiMarker>
</template>

Decorative Icons

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

<template>
  <UiMarker aria-label="Synced">
    <UiMarkerIcon>
      <Icon name="lucide:check" />
    </UiMarkerIcon>
  </UiMarker>
</template>

Interactive Markers

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

<template>
  <UiMarker as-child>
    <a href="/files">
      <UiMarkerIcon>
        <Icon name="lucide:file-text" />
      </UiMarkerIcon>
      <UiMarkerContent>Explored 4 files</UiMarkerContent>
    </a>
  </UiMarker>
</template>

API Reference

All Marker parts render through Primitive. Use as to choose another element, or as-child to merge the component's attributes and styles onto the single element or component in its default slot.

Marker

The root marker element.

PropTypeDefaultDescription
variant"default" | "border" | "separator""default"The marker layout.
asPrimitiveProps["as"]"div"Element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classHTMLAttributes["class"]-Additional classes to apply to the root element.

MarkerIcon

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

PropTypeDefaultDescription
asPrimitiveProps["as"]"span"Element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classHTMLAttributes["class"]-Additional classes to apply to the icon slot.

MarkerContent

The marker text content.

PropTypeDefaultDescription
asPrimitiveProps["as"]"span"Element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classHTMLAttributes["class"]-Additional classes to apply to the content slot.