Marker

Status, notes, and separators for conversation threads.

Add status updates, system notes, bordered rows, and labeled dividers to a conversation. Pair with Message to build a thread.

Switched to a new branch
Thinking…
Conversation compacted
Explored 4 files
tsx
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"function GitBranchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M6 3v12" />      <circle cx="18" cy="6" r="3" />      <circle cx="6" cy="18" r="3" />      <path d="M18 9a9 9 0 0 1-9 9" />    </svg>  )}function SearchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <circle cx="11" cy="11" r="8" />      <path d="m21 21-4.3-4.3" />    </svg>  )}export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker>        <MarkerIcon>          <GitBranchIcon />        </MarkerIcon>        <MarkerContent>Switched to a new branch</MarkerContent>      </Marker>      <Marker>        <MarkerContent className="shimmer">Thinking…</MarkerContent>      </Marker>      <Marker variant="separator">        <MarkerContent>Conversation compacted</MarkerContent>      </Marker>      <Marker>        <MarkerIcon>          <SearchIcon />        </MarkerIcon>        <MarkerContent>Explored 4 files</MarkerContent>      </Marker>    </div>  )}

Installation

npx @arctis-sh/@arctis-sh/ui@latest add marker

Usage

import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"
<Marker>  <MarkerIcon>    <CheckIcon />  </MarkerIcon>  <MarkerContent>Explored 4 files</MarkerContent></Marker>

Composition

Marker
├── MarkerIcon
└── MarkerContent

Variants

Use variant to choose an inline, bordered, or separator layout.

Inline note
Section
Row boundary
tsx
import { Marker, MarkerContent } from "@/components/ui/marker"export function Example() {  return (    <div className="flex flex-col gap-6">      <Marker>        <MarkerContent>Inline note</MarkerContent>      </Marker>      <Marker variant="separator">        <MarkerContent>Section</MarkerContent>      </Marker>      <Marker variant="border">        <MarkerContent>Row boundary</MarkerContent>      </Marker>    </div>  )}

| Variant | Description | | --- | --- | | default | Inline marker for status, notes, and actions. | | border | Default alignment with a bottom border under the row. | | separator | Centered label with divider lines on each side. |

Status

For in-progress markers, set role="status" and pair with Spinner so assistive technology announces updates.

Compacting conversation
Running tests
tsx
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"import { Spinner } from "@/components/ui/spinner"export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker role="status">        <MarkerIcon>          <Spinner aria-hidden="true" role="presentation" aria-label="" />        </MarkerIcon>        <MarkerContent>Compacting conversation</MarkerContent>      </Marker>      <Marker role="status">        <MarkerIcon>          <Spinner aria-hidden="true" role="presentation" aria-label="" />        </MarkerIcon>        <MarkerContent>Running tests</MarkerContent>      </Marker>    </div>  )}

Shimmer

Add the shimmer class to MarkerContent for a streaming text effect. Pair it with a spinner or icon in MarkerIcon while work is in progress.

Thinking…
Thinking…
Reading 4 files
tsx
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"import { Spinner } from "@/components/ui/spinner"function SearchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <circle cx="11" cy="11" r="8" />      <path d="m21 21-4.3-4.3" />    </svg>  )}export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker>        <MarkerContent className="shimmer">Thinking…</MarkerContent>      </Marker>      <Marker role="status">        <MarkerIcon>          <Spinner aria-hidden="true" role="presentation" aria-label="" />        </MarkerIcon>        <MarkerContent className="shimmer">Thinking…</MarkerContent>      </Marker>      <Marker role="status">        <MarkerIcon>          <SearchIcon />        </MarkerIcon>        <MarkerContent className="shimmer">Reading 4 files</MarkerContent>      </Marker>    </div>  )}

Separator

Use variant="separator" for dates or section dividers in a thread.

Today
Worked for 42s
Conversation compacted
tsx
import { Marker, MarkerContent } from "@/components/ui/marker"export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker variant="separator">        <MarkerContent>Today</MarkerContent>      </Marker>      <Marker variant="separator">        <MarkerContent>Worked for 42s</MarkerContent>      </Marker>      <Marker variant="separator">        <MarkerContent>Conversation compacted</MarkerContent>      </Marker>    </div>  )}

Border

Use variant="border" to keep the default alignment and separate the next row.

Switched to release-candidate
Reviewed 8 related files
Opened implementation notes
tsx
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"function GitBranchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M6 3v12" />      <circle cx="18" cy="6" r="3" />      <circle cx="6" cy="18" r="3" />      <path d="M18 9a9 9 0 0 1-9 9" />    </svg>  )}function SearchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <circle cx="11" cy="11" r="8" />      <path d="m21 21-4.3-4.3" />    </svg>  )}function FileTextIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />      <path d="M14 2v4a2 2 0 0 0 2 2h4" />      <path d="M10 9H8" />      <path d="M16 13H8" />      <path d="M16 17H8" />    </svg>  )}export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker variant="border">        <MarkerIcon>          <GitBranchIcon />        </MarkerIcon>        <MarkerContent>Switched to release-candidate</MarkerContent>      </Marker>      <Marker variant="border">        <MarkerIcon>          <SearchIcon />        </MarkerIcon>        <MarkerContent>Reviewed 8 related files</MarkerContent>      </Marker>      <Marker variant="border">        <MarkerIcon>          <FileTextIcon />        </MarkerIcon>        <MarkerContent>Opened implementation notes</MarkerContent>      </Marker>    </div>  )}

With icon

MarkerIcon sits beside the content on one row.

Switched to a new branch
Explored 4 files
Syncing completed
tsx
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"function GitBranchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M6 3v12" />      <circle cx="18" cy="6" r="3" />      <circle cx="6" cy="18" r="3" />      <path d="M18 9a9 9 0 0 1-9 9" />    </svg>  )}function SearchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <circle cx="11" cy="11" r="8" />      <path d="m21 21-4.3-4.3" />    </svg>  )}function CheckIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M5 13l4 4L19 7" />    </svg>  )}export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker>        <MarkerIcon>          <GitBranchIcon />        </MarkerIcon>        <MarkerContent>Switched to a new branch</MarkerContent>      </Marker>      <Marker>        <MarkerIcon>          <SearchIcon />        </MarkerIcon>        <MarkerContent>Explored 4 files</MarkerContent>      </Marker>      <Marker>        <MarkerIcon>          <CheckIcon />        </MarkerIcon>        <MarkerContent>Syncing completed</MarkerContent>      </Marker>    </div>  )}

Pass render to turn the root into a real <a> or <button>.

View the pull request
tsx
"use client"import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"function GitBranchIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M6 3v12" />      <circle cx="18" cy="6" r="3" />      <circle cx="6" cy="18" r="3" />      <path d="M18 9a9 9 0 0 1-9 9" />    </svg>  )}function RotateCcwIcon({ className }: { className?: string }) {  return (    <svg      viewBox="0 0 24 24"      fill="none"      stroke="currentColor"      strokeWidth="2"      strokeLinecap="round"      strokeLinejoin="round"      aria-hidden="true"      className={className}    >      <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />      <path d="M3 3v5h5" />    </svg>  )}export function Example() {  return (    <div className="flex flex-col gap-3">      <Marker render={<a href="#" />}>        <MarkerIcon>          <GitBranchIcon />        </MarkerIcon>        <MarkerContent>View the pull request</MarkerContent>      </Marker>      <Marker render={<button type="button" />} onClick={() => undefined}>        <MarkerIcon>          <RotateCcwIcon />        </MarkerIcon>        <MarkerContent>Revert this change</MarkerContent>      </Marker>    </div>  )}
<Marker render={<a href="/pr/42" />}>  <MarkerContent>View the pull request</MarkerContent></Marker>

Accessibility

Markers are presentational by default. Choose semantics based on their purpose.

Status — for streaming or progress, set role="status" so assistive tech announces the update. Hide decorative spinners inside MarkerIcon.

Separators — labeled dividers need no role. Divider lines are decorative CSS. Do not put role="separator" on a labeled marker; that role ignores text content and takes its name from aria-label.

IconsMarkerIcon is aria-hidden. For icon-only markers, add aria-label (or visible text).

Interactive — use render with a real link or button so the control is reachable and correctly named by its content.

API Reference

Marker

Root element. markerVariants is also exported for composing styles. Standard HTML attributes such as role, onClick, and aria-label pass through to the root or the element provided through render.

PropTypeDefault
variant"default" | "border" | "separator""default"
renderReactElement
classNamestring
<Marker>  <MarkerContent>Explored 4 files</MarkerContent></Marker>

MarkerIcon

Decorative icon slot. Always aria-hidden. Accepts native span props.

PropTypeDefault
classNamestring
<MarkerIcon>  <CheckIcon /></MarkerIcon>

MarkerContent

Text content for the marker. Accepts native span props. Use className="shimmer" for the streaming text effect.

PropTypeDefault
classNamestring
<MarkerContent>Explored 4 files</MarkerContent>