Skip to content
Glint UI

Marker

The inline transcript annotation — a status line, a system note, and the labeled divider between one day's messages and the next.

Usage

import { Marker, MarkerVariant } from "@glint/components/marker.slint";
export component AppWindow inherits Window {
in property <bool> working;
VerticalLayout {
spacing: 12px;
// The divider between two days of a transcript.
Marker {
text: "Yesterday";
variant: MarkerVariant.separator;
}
// A system note between two turns.
Marker { text: "Ada joined the conversation"; }
// A status line while a tool call is in flight. `busy` is what makes
// it a live region, so it is announced as it arrives.
if root.working: Marker {
text: "Running the test suite";
busy: true;
shimmer: true;
}
}
}

A marker is the row a transcript says something in its own voice: a divider, a system note, a status line. It is one label, optionally with a leading glyph, and it is announced as one node — a piece of text while it is inert, a button once interactive makes it one.

It is the annotation with a divider variant, not a divider with a label. Separator already draws a captioned rule, and MarkerVariant.separator reuses it for the two halves it centers the label between. What a rule cannot carry is a leading glyph, a Spinner, a live region or an activation — and a transcript’s dividers need all four, which is why this component exists at all.

Everything on the row is the consumer’s: Glint formats no dates, counts nothing, and picks no icon. text is what the row says and what assistive technology reads.

Examples

Variants

default is the bare row. border draws a rule under it, which separates a note from what follows without spending a line on a divider. separator centers the label between two rules that take the rest of the width — the “Today” divider.

Busy, and the shimmer

busy swaps the glyph for a Spinner and turns the row into a polite live region, so a status arriving mid-stream is announced without interrupting whatever the reader is doing. shimmer is the streaming treatment on the label: the pulse Skeleton breathes with, on the same 800ms rhythm. It is not shadcn’s moving gradient — a gradient sweeping across glyphs needs a shader Slint 1.17 does not expose.

The pulse only ticks while there is one to draw, so a still marker keeps nothing awake.

An interactive marker

interactive makes the whole row a control — “3 messages hidden, show them”, “retry”. The pointer, Enter, Space and the accessible default action all land on the same clicked, and action-label names it where the note is not the whole story. A marker that is not interactive is not a control: nothing announces it as one, and Tab has nothing to land on.

API Reference

Properties

PropertyTypeDefaultDescription
variantin MarkerVariantMarkerVariant.defaultWhich of the three shapes to draw.
textin stringno defaultThe note itself.
iconin LucideIconno defaultLeading glyph, normally selected from IconSet in lucide-slint. Left unset the row is the label alone; busy replaces it with a Spinner.
busyin boolfalseSomething is happening: the glyph becomes a Spinner and the row starts announcing itself politely.
shimmerin boolfalseThe streaming treatment on the label — see the note in the header for what it is and what it is not.
interactivein boolfalseMakes the whole row a control. A marker that is not interactive has nothing for Tab to land on.
action-labelin stringroot.textWhat assistive technology announces the control as. The note says it for the common case; override it where the note is not the whole story.

Callbacks

CallbackDescription
clicked()Fired when an interactive row is activated by pointer, by Enter or Space, or through the accessible default action.

Enums

EnumValues
MarkerVariantdefault, border, separator

Accessibility

  • The row speaks once. A marker is a single node in the tree: a piece of text while it is inert, and a button once interactive makes it one. Neither is layered over the other — Slint requires accessible-role to be a constant, so the two are if-guarded siblings and the row picks one (ADR-0026).
  • busy is a polite live region, which is how a status that arrives mid-stream is announced without interrupting the reader — the same mechanism MessageScroller uses for an arriving turn.
  • The rules are decorative. A separator marker announces its label and never the hairlines around it, so a divider does not read as content.
  • The glyph is decorative too. The icon and the busy spinner carry no role: the label is what is announced, and a second node would say it twice.
  • Keyboard. An interactive marker is one tab stop that Enter and Space fire; a marker that is not interactive takes no tab stop at all, because an affordance that does nothing must not collect one.
  • Keyboard-only focus ring, drawn around the row when the keyboard put the focus there and not when the pointer did.
  • action-label names the control for assistive technology, defaulting to text. Override it where the note reads as a statement rather than as what activating the row will do.