Skip to main content

Badge

Info:Feedback
103

A compact label, tag, or status chip: three fills across six semantic tones and twelve named hues, optionally removable.

tag chip pill label status count counter dot

Live demo

live · @xtyle/astro

Badge

Three fills, six semantic tones

solid

accent neutral Success:success Warning:warn Danger:danger Info:info

soft

accent neutral Success:success Warning:warn Danger:danger Info:info

outline

accent neutral Success:success Warning:warn Danger:danger Info:info

Every tone

Accents

accent accent-2 accent-3 accent-4 neutral

Statuses

Success:success Info:info Warning:warn Danger:danger

Named hues

red orange yellow green blue purple brown pink cyan gray white black

Sizes, dots, counts, and dismissal

small medium large
Success:Live Warning:Degraded Danger:Offline Info:Inbox12 Alerts99+
design frontend tokens

Live status

A pulse breathes the dot so a chip reads as live, at Progress's two speeds (slow and fast). It holds still under reduced-motion, and a plain dot stays static for contrast.

Success:Live Streaming Danger:Alert Idle

The same breathe drives the standalone .xtyle-dot for a chip-less live pip, a connection light or a per-row streaming indicator with no label around it.

Connected

Streaming

Offline

For a live status light that needs to grab the eye, --ping radiates an expanding ring, --glow adds a soft halo, and an inline --dot-color paints an arbitrary color past the tone classes (a per-state color from an app's own map). All held still under reduced-motion.

Recording

Live (ping + glow)

Custom color

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.

Pair with a list or tag input as removable chips; wire onremove (svelte) or the .xtyle-badge__remove click (html/astro) to drop the item.
Use the standalone .xtyle-dot indicator next to avatars or rows for presence without a full chip; make a chip-less dot read as live with --pulse-slow/--pulse-fast (opacity breathe), --ping (an expanding ring for a stronger status light), and --glow (a soft halo), composable together and all held still under reduced-motion. Reach past the tone classes with an inline --dot-color when an app's per-state color map is wider than the tone set.
The count affordance pairs with nav items and tabs for unread counts.

Props

9 props, straight from the manifest.

PropTypeDefaultBindingsDescription
variant BadgeVariant
solid soft outline
soft
html svelte astro
Fill treatment. Independent of tone.
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
neutral
html svelte astro
Any color tone: a semantic role, an accent variant (accent-2/3/4), or a named hue (red … black).
size Size
sm md lg
md
html svelte astro
Chip size; the scale tops out smaller than the controls (no `xl`).
dot boolean false
html svelte astro
Shows a leading status dot in the current text color.
pulse boolean | "slow" | "fast"
slow fast
html svelte astro
Breathes the `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`.
count string | number
html svelte astro
A numeric count rendered after the label in tabular figures.
removable boolean false
html svelte astro
Adds a dismiss `×` button. html/svelte wire it to fire `onremove`; Astro emits static markup you wire yourself.
removeLabel string Remove
html svelte astro
Accessible name for the dismiss button (kebab `remove-label` on the custom element).
onremove (event: MouseEvent) => void
svelte
Handler invoked when the dismiss button is activated.

Appearance

Variants

solid

.xtyle-badge--solid

Filled with the tone color. The highest-emphasis treatment.

soft

.xtyle-badge--soft

A soft tone-tinted background with tone-colored text. The default.

outline

.xtyle-badge--outline

Transparent fill with a tone-colored border and text.

Sizes

sm

.xtyle-badge--sm

Compact.

md

default
.xtyle-badge

Default.

lg

.xtyle-badge--lg

Large.

States

pulse

.xtyle-badge--pulse-slow .xtyle-badge__dot, .xtyle-badge--pulse-fast .xtyle-badge__dot

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

.xtyle-badge__remove:hover::after

Pointer over the dismiss button. Its overlay paints the hover tint.

remove-active

.xtyle-badge__remove:active::after

Dismiss button pressed. Its overlay paints the press tint.

remove-focus-visible

.xtyle-badge__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, with their selectors.

badge

.xtyle-badge

The chip root carrying the variant, tone, and size classes.

--font-sans --text-xs --weight-medium --leading-tight --neutral-bg --neutral-text --border-thin --radius-full --space-0 --space-2

dot

.xtyle-badge__dot

The optional leading status dot, painted in the badge's current text color; breathes on a soft opacity loop when pulse is set.

--space-2 --space-3 --radius-full --ease-standard

label

.xtyle-badge__label

The text content wrapper.

count

.xtyle-badge__count

A tabular-numeric count affordance rendered after the label.

--weight-semibold

remove

.xtyle-badge__remove

A real <button> dismiss control with an accessible name, its own focus ring, and a state overlay.

--space-1 --radius-full --duration-fast --ease-standard --state-hover --state-press --border-normal --border-thick --ring

indicator

.xtyle-dot

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.

--space-1 --space-2 --space-3 --radius-full --border-thin --neutral --ease-standard

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 103/103 consumed tokens produced default register: 299 tokens

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-text

Slots

default
html svelte astro

The badge label.

Accessibility

Status tones (success, warn, danger, info) emit a screen-reader-only tone word, so meaning is conveyed without relying on color (WCAG 1.4.1).
The leading dot is decorative (aria-hidden); the standalone .xtyle-dot should carry role="img" and an aria-label when it conveys meaning on its own.
The pulse animation is purely decorative and is disabled under prefers-reduced-motion; the live meaning should also be carried by the label text, never by the motion alone.
The dismiss control is a native <button> with an aria-label; the html/svelte bindings warn at runtime when you omit remove-label.
The dismiss button shows focus with a token ring plus a transparent outline that the forced-colors base rule promotes to a real system outline.
The × glyph is drawn as a decorative aria-hidden SVG; the button's accessible name comes from its label, not the icon.

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>