{#snippet sparkIcon()} {/snippet}
Status · Badge

Badge

Small inline label / status pill. Four visual variants (soft, solid, outline, ghost), four sizes, eight color accents, four rounded scales, and optional dot · icon · remove slots. Eidos-native: no semantic events, no soma split — the morfo declares five parts and the recipe paints the chip from the canonical color palette.

parts{compiled.parts.order.length} events0 variants{variants.length} sizes{sizes.length} colors{colors.length} scopeeidos
{labelText || 'Badge'}
trace {trace.length === 0 ? 'no semantic events' : `${trace.length} event(s)`} · removes {removeCount} variant {variant} · size {size} · color {color}
{#if tab === 'live'}

Controls

Badge is eidos-native — no soma split. Variants stretch over the same chrome (padding, radius, font). The optional Dot / Icon / Remove slots compose inline next to the label; toggle them independently.

eidos props · visual treatment
eidos visual · slots compose inline svelte
{eidosSnippet}
Patterns · common shapes
status pill Active Pending Failed Archived Draft shape families rounded continuous cut scoop count chip 3 12 99+ new filter tags Engineering Design Product with icon Premium Beta Limited inline label Subscription Active Build #4218 latest API v2 deprecated
{/if} {#if tab === 'api'}

API reference

Badge composes through <Box> so consumers can apply layout primitives (gridColumn, margin, …) without wrapping. The five Badge-specific props are independent — you can render a label-only badge, a dot-only chip, an icon + label, or a removable tag without touching the others.

Badge-specific props
PropTypeNotes
variant 'soft' | 'solid' | 'outline' | 'ghost' soft (default) — tinted bg + text. solid — filled bg + contrast text. outline — border-only. ghost — text only.
size 'xs' | 'sm' | 'md' | 'lg' Drives padding · gap · font-size. Default md. No xl — badges are inline labels, a larger size competes with body type.
color ColorRole Full 8-step palette. Map status semantics directly: affirm → success, risk → warning, threat → error, loss → archived / muted.
rounded 'sm' | 'md' | 'lg' | 'full' Corner radius. Default full (pill). md/lg for a soft-rect look at any size.
dot boolean Render a small coloured circle before the label — status-pill style. Uses the solid palette step so it reads even on soft / outline / ghost variants.
icon Snippet? Optional snippet rendered before the label. Sized via --badge-icon-size (1em — scales with the badge font-size).
removable boolean Render an X button at the trailing edge. Use for filter chips / dismissable tags.
onRemove () => void Callback fired when the user activates the remove button.
removeLabel string? Override the remove button's accessible label. Defaults to the translated 'Remove'.
Reference comparison
LibraryClosest equivalentDifference
shadcn/ui <Badge> shadcn ships 4 variants (default/secondary/destructive/outline). UIX adds the 8-color matrix, ghost variant, and built-in dot / icon / removable slots.
radix-themes <Badge> Radix has variant + radius + color + high-contrast. UIX drops high-contrast (handled by solid) and adds dot + removable as first-class props instead of consumer-composed children.
chakra-ui <Tag> / <Badge> Chakra splits Tag (with CloseButton) and Badge (label only). UIX collapses both into one primitive — removable turns a badge into a tag.
mantine <Badge> Mantine has leftSection / rightSection for icons. UIX uses a typed icon snippet for the leading slot; the trailing slot is reserved for removable.
ark-ui — Ark doesn't ship a Badge — it's pure visual without a behavior surface (no open / close / select to coordinate). UIX places it in eidos for the same reason.
{/if} {#if tab === 'morfo'}

Morfo contract

FieldValue
name{badgeMorfo.name}
kebab{badgeMorfo.kebab}
scope{badgeMorfo.scope.join(', ')}
parts{partsList.length}
events0
Parts
{#each partsList as part (part.kebab)} {/each}
kebab marker element archetype role optional
{part.kebab} [{part.marker}] <{part.defaultElement}> {part.archetype ?? '—'} {part.role ?? '—'} {part.optional ? 'yes' : 'no'}
Dot · aria
attrvalueseverity
aria-hidden "true" literal
Icon · aria
attrvalueseverity
aria-hidden "true" literal
Remove · aria
attrvalueseverity
role button part default
type "button" literal
aria-label translationRef('components.badge.remove') recommended
{/if} {#if tab === 'sema'}

sema · events

Badge declares no semantic events. The chip is perceptual chrome — a label, status pill, or tag — not a behavior surface. The optional Remove button emits a click but the canonical shape for "user clicked the X" is the consumer's onRemove handler, not a sema event the engine should route.

If you need a perceptual cue when a badge appears or removes (e.g. a tag added to a filter list), attach it to the parent action — the TagsInput's commit-add / commit-remove, the search field's filter update, etc.

{/if} {#if tab === 'recipe'}

Eidos recipe

Recipe lives in src/uix/eidos/components/badge/badge.css. All variants share private tokens (--_badge-bg, --_badge-fg, --_badge-border-color) set per variant + color cascade so the rules below stay flat. The recipe surface (--badge-*) feeds the canonical accent slots (track / border / solid / text / contrast).

SelectorOwnerPurpose
[data-badge] morfo Provider marker. Inline-flex chrome (padding, radius, font, border).
[data-badge][data-size='xs'..'lg'] eidos Sets --_badge-px · --_badge-py · --_badge-gap · --_badge-font-size.
[data-badge][data-rounded='sm'..'full'] eidos Sets --_badge-radius.
[data-badge][data-color='primary'..'loss'] eidos Cascades track / border / solid / text / contrast from the canonical 8-color palette.
[data-badge][data-variant='soft'..'ghost'] eidos Picks which palette slot becomes --_badge-bg / --_badge-fg / --_badge-border-color.
[data-badge-dot] morfo Status dot — small filled circle, always uses the solid palette step.
[data-badge-icon] morfo Icon slot — sized 1em so it scales with the badge font-size.
[data-badge-label] morfo Label wrapper around the children text.
[data-badge-remove] morfo Remove button — circular X with hover tint. Focus-visible paints the global focus ring.
All variants × colors (size = md)
{#each variants as v (v)} {v} {#each colors as c (c)} {c} {/each} {/each}
All sizes × rounded (variant = soft, color = primary)
{#each sizes as s (s)} {s} {#each roundeds as r (r)} {r} {/each} {/each}
Slot matrix · dot · icon · removable
label only dot icon removable dot + icon icon + remove dot + remove
{/if} {#if tab === 'a11y'}

Accessibility

ConcernContract
Provider role Default <span>, no implicit role. Screen readers read the inline text alongside surrounding context — the badge is read as part of the sentence it sits in, which is the right default for status / count chips.
Decorative slots data-badge-dot and data-badge-icon are aria-hidden="true". The label text alone carries semantic meaning. Don't communicate state through the dot color only — pair it with a word ("Active", "Failed").
Remove button <button type="button"> with translated aria-label="Remove". Activates via Enter / Space. stopPropagation prevents the click from bubbling to a parent interactive element (e.g. the row a filter tag sits in).
Focus visible Only the remove button is focusable. Focus ring uses the global --focus-ring-* tokens.
Color contrast Each color × variant pair is auto-balanced by the canonical palette (track + text for soft / outline / ghost, solid + contrast for solid). Tested against WCAG AA for normal text at all sizes ≥ sm.
High-contrast mode outline variant survives forced-colors (border + text use currentColor). ghost degrades to text-only — acceptable for label use, not for status pills (use soft or solid there).
When to use Status pills, count chips, tags, version markers. For interactive selection use <TagGroup>; for user-typed tags use <TagsInput>; for filter chips use <ToggleGroup> with variant="chip".
{/if}