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.
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
eidosvisual · slots compose inlinesvelte
{eidosSnippet}
Patterns · common shapes
status pillActivePendingFailedArchivedDraftshape familiesroundedcontinuouscutscoopcount chip31299+newfilter tags
Engineering
Design
Product
with iconPremiumBetaLimitedinline 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.
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
Library
Closest equivalent
Difference
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
Field
Value
name
{badgeMorfo.name}
kebab
{badgeMorfo.kebab}
scope
{badgeMorfo.scope.join(', ')}
parts
{partsList.length}
events
0
Parts
kebab
marker
element
archetype
role
optional
{#each partsList as part (part.kebab)}
{part.kebab}
[{part.marker}]
<{part.defaultElement}>
{part.archetype ?? '—'}
{part.role ?? '—'}
{part.optional ? 'yes' : 'no'}
{/each}
Dot · aria
attr
value
severity
aria-hidden
"true"
literal
Icon · aria
attr
value
severity
aria-hidden
"true"
literal
Remove · aria
attr
value
severity
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).
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".