Badge
A compact label, tag, or status chip: three fills across six semantic tones and twelve named hues, optionally removable.
Live demo
Badge labels, tags, counts, and statuses inline. Fill treatment (variant) and color (tone) are independent axes: each of the three fills (solid, soft, outline) can carry any of the six semantic tones (accent, neutral, danger, success, warn, info) or any of the twelve named hues (red … black).
It adds a leading status dot (which can pulse to read as live), a tabular count affordance, and a removable form whose × is a real focusable <button> that emits a remove event. That's the removable tag you build a filter row or token input from. A standalone .xtyle-dot indicator covers the bare-dot case. Status tones (success, warn, danger, info) emit a screen-reader-only tone word so meaning never rides on color alone.
When to use
How this component composes with the rest of the set.
Props
9 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
xl). | ||||
dot on a soft opacity loop so the chip reads as live (streaming, connected, active), reusing Progress's pulse cadence: a bare pulse (or slow) runs at 1.8s, fast at 0.9s. No-op without dot, and held still under prefers-reduced-motion. | ||||
× button. html/svelte wire it to fire onremove; Astro emits static markup you wire yourself. | ||||
remove-label on the custom element). | ||||
Appearance
Variants
solid
Filled with the tone color. The highest-emphasis treatment.
soft
A soft tone-tinted background with tone-colored text. The default.
outline
Transparent fill with a tone-colored border and text.
Sizes
sm
Compact.
md
Default.
lg
Large.
States
pulse
With pulse and a dot, the dot breathes on a soft opacity loop at Progress's own two speeds (slow 1.8s, fast 0.9s); held still under prefers-reduced-motion.
remove-hover
Pointer over the dismiss button. Its overlay paints the hover tint.
remove-active
Dismiss button pressed. Its overlay paints the press tint.
remove-focus-visible
Keyboard focus on the dismiss button: a token ring plus a transparent outline that becomes real in forced-colors mode.
Anatomy
The named parts that make up the component. A ::part() handle is reachable from your own stylesheet; the class beside it is the component's internal selector, which a shadow boundary keeps to itself.
badge
The chip root carrying the variant, tone, and size classes.
dot
The optional leading status dot, painted in the badge's current text color; breathes on a soft opacity loop when pulse is set.
label
The text content wrapper.
count
A tabular-numeric count affordance rendered after the label.
remove
A real <button> dismiss control with an accessible name, its own focus ring, and a state overlay.
indicator
A standalone dot indicator independent of any chip, tonable and sizable on its own. It reads as live three ways, composable: --pulse-slow / --pulse-fast breathe its opacity, --ping radiates an expanding ring (a stronger, attention-grabbing status light), and --glow adds a soft halo. Its color comes from the tone class, or from an inline --dot-color custom property for an arbitrary per-state color the tone set can't name.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent--accent-2--accent-2-bg--accent-2-fg--accent-2-text--accent-3--accent-3-bg--accent-3-fg--accent-3-text--accent-4--accent-4-bg--accent-4-fg--accent-4-text--accent-bg--accent-fg--accent-text--black--black-bg--black-fg--black-text--blue--blue-bg--blue-fg--blue-text--border-normal--border-thick--border-thin--brown--brown-bg--brown-fg--brown-text--cyan--cyan-bg--cyan-fg--cyan-text--danger--danger-bg--danger-fg--danger-text--duration-fast--ease-standard--font-sans--gray--gray-bg--gray-fg--gray-text--green--green-bg--green-fg--green-text--info--info-bg--info-fg--info-text--leading-tight--neutral--neutral-bg--neutral-fg--neutral-text--orange--orange-bg--orange-fg--orange-text--pink--pink-bg--pink-fg--pink-text--purple--purple-bg--purple-fg--purple-text--radius-full--red--red-bg--red-fg--red-text--ring--space-0--space-1--space-2--space-3--state-hover--state-press--success--success-bg--success-fg--success-text--text-sm--text-xs--warn--warn-bg--warn-fg--warn-text--weight-medium--weight-semibold--white--white-bg--white-fg--white-text--yellow--yellow-bg--yellow-fg--yellow-textSlots
The badge label.
Accessibility
Code
Fills, tones, and affordances
The three fills cross all tones and hues; dot, count, and the removable form layer on top, with a standalone dot for the bare case.
<xtyle-badge variant="soft" tone="accent">New</xtyle-badge>
<xtyle-badge variant="solid" tone="success" dot>Online</xtyle-badge>
<xtyle-badge variant="outline" tone="danger">Failed</xtyle-badge>
<xtyle-badge tone="info" count="12">Notifications</xtyle-badge>
<xtyle-badge variant="soft" tone="purple" removable remove-label="Remove tag">design</xtyle-badge>
<span class="xtyle-dot xtyle-dot--success" role="img" aria-label="Online"></span><script lang="ts">
import { Badge } from "@xtyle/svelte";
</script>
<Badge variant="soft" tone="accent">New</Badge>
<Badge variant="solid" tone="success" dot>Online</Badge>
<Badge variant="outline" tone="danger">Failed</Badge>
<Badge tone="info" count={12}>Notifications</Badge>
<Badge variant="soft" tone="purple" removable removeLabel="Remove tag" onremove={() => drop("design")}>design</Badge>---
import { Badge } from "@xtyle/astro";
---
<Badge variant="soft" tone="accent">New</Badge>
<Badge variant="solid" tone="success" dot>Online</Badge>
<Badge variant="outline" tone="danger">Failed</Badge>
<Badge tone="info" count={12}>Notifications</Badge>
<Badge variant="soft" tone="purple" removable removeLabel="Remove tag">design</Badge>
<span class="xtyle-dot xtyle-dot--success" role="img" aria-label="Online"></span>Live status
pulse breathes the dot so a chip reads as live, streaming, or connected, at Progress's two speeds (slow and fast); it holds still under reduced-motion.
<xtyle-badge variant="soft" tone="success" dot pulse>Live</xtyle-badge>
<xtyle-badge variant="soft" tone="danger" dot pulse="fast">Alert</xtyle-badge><script lang="ts">
import { Badge } from "@xtyle/svelte";
</script>
<Badge variant="soft" tone="success" dot pulse>Live</Badge>
<Badge variant="soft" tone="danger" dot pulse="fast">Alert</Badge>---
import { Badge } from "@xtyle/astro";
---
<Badge variant="soft" tone="success" dot pulse>Live</Badge>
<Badge variant="soft" tone="danger" dot pulse="fast">Alert</Badge>Standalone status dot: breathe, ping, glow, custom color
The chip-less .xtyle-dot reads as live three composable ways (opacity breathe, an expanding --ping ring, and a --glow halo) and takes an arbitrary color through the inline --dot-color escape hatch when the tone set can't name it.
<!-- Tone-colored breathe (opacity loop) -->
<span class="xtyle-dot xtyle-dot--success xtyle-dot--pulse-slow" role="img" aria-label="Connected"></span>
<!-- Expanding ping ring for a live status light -->
<span class="xtyle-dot xtyle-dot--danger xtyle-dot--ping" role="img" aria-label="Recording"></span>
<!-- Ping + glow, larger -->
<span class="xtyle-dot xtyle-dot--success xtyle-dot--ping xtyle-dot--glow xtyle-dot--lg" role="img" aria-label="Live"></span>
<!-- Arbitrary color past the tone classes, via the --dot-color escape hatch -->
<span class="xtyle-dot xtyle-dot--glow" style="--dot-color: var(--purple)" role="img" aria-label="Queued"></span>