defuss-shadcn / Chat / marker
MarkerATM
The quiet lines between the messages of a conversation: an inline status ("Explored 4 files"), a step in progress with a spinner, streaming "Thinking…" text, a bordered row, or a labeled separator ("Today"). An icon slot and the words - muted, so they never compete with the bubbles. CSS only, after shadcn/ui's Marker.
On this page (13)
§Marker
An icon (decorative - aria-hidden) and the words; muted and sized to its content, so it sits between messages without competing with them.
§Variants
default - inline; border - a full-width row with a rule under it; separator - a centered label between two rules.
§Status with a spinner
A step in progress: the shipped spinner in the icon slot and role='status', so the change is announced politely.
§Shimmer
data-shimmer on the content sweeps a light band across the words - streaming text while a model thinks. Plain muted text under reduced motion.
§Separator
A date divider in a thread, with inline status markers under it.
§Border
Bordered rows separate the steps of an agent run - each one full width with a rule under it.
§Stacked
data-orientation='vertical' puts the icon above the words, centered - an empty state or the start of a thread.
§Tones
data-tone colors the icon only - success, warning, info, destructive, primary; the words stay quiet and still say what happened.
§Links and buttons
When the marker is an action, render it as a real <a> or <button class='marker'> - focusable, underlined on hover.
§In a conversation
Markers between bubbles: the date, what the assistant did, and the reply.
§Sizes
data-size sm · (default) · lg - the icon scales with the words.
§Right to left
Logical throughout - the icon leads on the right in dir='rtl'.
§CSS view file
/* -- Marker component ------------------------------------------------ *//* An inline status, system note, bordered row or labeled separator in a conversation ("Explored 4 files", "Today", "Conversation compacted"). CSS only; a spinner / icon goes in .marker-icon, the words in .marker-content. */@layer components { .marker { --_ic: currentColor; display: flex; align-items: center; gap: 0.5rem; width: fit-content; max-width: 100%; padding-block: 0.25rem; font-size: 0.8125rem; line-height: 1.4; color: var(--muted-foreground); text-align: start; /* -- Variants -------------------------------------------------- */ /* border: a full-width row with a rule under it */ &[data-variant="border"] { width: 100%; padding-block: 0.5rem; border-block-end: 1px solid var(--border); } /* separator: a centered label between two rules ("Today") */ &[data-variant="separator"] { width: 100%; justify-content: center; gap: 0.75rem; font-size: 0.75rem; font-weight: 500; &::before, &::after { content: ""; flex: 1 1 0; min-width: 1rem; height: 1px; background: var(--border); } } /* stacked: the icon above the words, centered */ &[data-orientation="vertical"] { flex-direction: column; gap: 0.375rem; text-align: center; &:not([data-variant="separator"], [data-variant="border"]) { margin-inline: auto; } } /* -- Tones: color the icon (the words stay quiet) -------------- */ &[data-tone="success"] { --_ic: oklch(0.6 0.15 150); } &[data-tone="warning"] { --_ic: oklch(0.72 0.16 70); } &[data-tone="info"] { --_ic: oklch(0.6 0.16 250); } &[data-tone="destructive"] { --_ic: var(--destructive); } &[data-tone="primary"] { --_ic: var(--primary); } /* -- Sizes ------------------------------------------------------ */ &[data-size="sm"] { font-size: 0.75rem; gap: 0.375rem; & .marker-icon { font-size: 0.875rem; } } &[data-size="lg"] { font-size: 0.875rem; & .marker-icon { font-size: 1.125rem; } } } .marker-icon { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; font-size: 1rem; line-height: 1; color: var(--_ic); & svg { width: 1em; height: 1em; } } .marker-content { min-width: 0; text-wrap: pretty; overflow-wrap: anywhere; & strong, & b { font-weight: 600; color: var(--foreground); } & code { font-family: var(--font-mono); font-size: 0.92em; color: var(--foreground); } } /* -- Shimmer: streaming text ("Thinking…") - a light band sweeps across the words (background-clip: text) ------------------------ */ .marker-content[data-shimmer] { color: transparent; background: linear-gradient( 90deg, var(--muted-foreground) 0%, var(--muted-foreground) 35%, var(--foreground) 50%, var(--muted-foreground) 65%, var(--muted-foreground) 100% ) 0 0 / 250% 100%; -webkit-background-clip: text; background-clip: text; animation: marker-shimmer 1.8s linear infinite; } @keyframes marker-shimmer { from { background-position: 100% 0; } to { background-position: 0% 0; } } /* -- Interactive: the whole marker as a link or a button ----------- */ :is(a, button).marker { appearance: none; border: 0; border-radius: var(--radius-sm); background: none; font: inherit; font-size: 0.8125rem; color: var(--muted-foreground); text-decoration: none; cursor: pointer; transition: color 150ms ease; &:hover { color: var(--foreground); & .marker-content { text-decoration: underline; text-underline-offset: 2px; } } &:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } &:disabled { opacity: 0.5; pointer-events: none; } } :is(a, button).marker[data-variant="border"] { border-radius: 0; border-block-end: 1px solid var(--border); }}@media (prefers-reduced-motion: reduce) { @layer components { .marker-content[data-shimmer] { animation: none; color: var(--muted-foreground); background: none; } :is(a, button).marker { transition: none; } }}@media (prefers-contrast: more) { @layer components { .marker { color: var(--foreground); } .marker[data-variant="separator"]::before, .marker[data-variant="separator"]::after { background: var(--foreground); } }}@media (forced-colors: active) { @layer components { .marker { color: CanvasText; } .marker-icon { color: CanvasText; } .marker[data-variant="separator"]::before, .marker[data-variant="separator"]::after { background: CanvasText; } .marker-content[data-shimmer] { color: CanvasText; background: none; } :is(a, button).marker { color: LinkText; } }}Comments, ideas or improvements? Edit this page's source on GitHub