Susegad UI
Register
Theme
Palette

Components

Badge

A word or two of status. The text is the meaning, a distinct shape per tone backs it up, colour comes last. Quiet is text with a hairline rule; warm is a hand-inked outline in the tone's ink; playful is a chip of colour with a kolam flower on the corner.

quiet warm playful

Open the live demo npx susegad add badge

Stands on: Core, Core: components, Engine, Tokens

The prompt

the prompt

A word or two of status beside the thing it describes: Paid, Draft, Overdue, Saving.

The word is the meaning. A small shape for each tone backs it up for anyone who cannot tell the colours apart, and colour comes last.

<link rel="stylesheet" href="susegad/components/badge/badge.css">
<script type="module" src="susegad/components/badge/badge.js"></script>

<sg-badge tone="success">Paid</sg-badge>
<sg-badge tone="warning">Deposit due</sg-badge>
<sg-badge tone="info" busy>Saving</sg-badge>
AttributeValuesWhat it does
toneneutral, accent, success, warning, danger, infoThe ink and the shape: a ring, a diamond, a tick, a triangle, a cross, a circled i.
busypresent or absentThe thing is still happening. The words must say so ("Saving", "Checking payment"); the mark moves only in warm and playful.
seedany word or numberThe hand-inked outline in warm. Defaults to the text.

The prompt

Make a status badge web component that is just text: <sg-badge tone="success">Paid</sg-badge>. Never let colour carry the meaning alone. Put a small shape before the words, a different outline for each tone (a ring for neutral, a diamond for accent, a tick for success, a triangle with a bar for warning, a cross for danger, a circled i for info), drawn as a CSS mask on an empty pseudo-element so a screen reader reads only the words. Without JavaScript, show the words in the text colour, the shape in the tone's colour, and a hairline rule around them. Give it three registers. Quiet: exactly that, and nothing moves. Warm: replace the rule with a hand-inked outline in the tone's ink, drawn twice like a nib going round, nudged by seeded noise and closed with a small overlap where the pen passes its start; fit it to the badge's size and redraw when the words change. Playful: fill the badge with the tone as a rounded chip, set the words in the page colour on it, and stick a tiny kolam flower on the top-right corner like a sticker, so it reads as ornament and never as a button. When a badge is busy, breathe the shape slowly in warm and turn the kolam in playful, pause both off screen, and keep everything still under reduced motion. Check that the chip's text meets 4.5:1 on its fill in every palette and theme.

Words to code

When you sayTechniqueWhat happens
never let colour carry the meaning aloneredundancyThe word always carries the meaning. ICONS holds six outlines on a 12 × 12 grid, all different, and a test checks they stay different and that badge.css carries exactly those shapes.
a CSS mask on an empty pseudo-elementnative first::before { content: ""; mask: var(--sg-badge-icon) }. With no content text there is nothing for assistive tech to read twice, and it works with no JavaScript.
drawn twice like a nib going round … closed with a small overlapnoiseinkOutline(w, h, seed) resamples a rounded rectangle every 4 px and pushes each point out from the centre by seeded Perlin noise, scaled by the register's --sg-wobble. The second pass is finer, offset and fainter. The path runs a few points past its start.
fit it to the badge's sizelayoutA ResizeObserver redraws the path at the badge's fractional size, with preserveAspectRatio="none". A viewBox a fraction off scaled the whole outline in towards the words.
like a sticker … never as a buttonaffordanceA trailing icon on a chip reads as "remove" or "add". The kolam flower sits on the corner, overlapping the edge, where controls never go.
breathe … turn … pause both off screencalmbusyMotion(motion) returns nothing for quiet and reduced motion, an opacity breath for warm, and a slow turn for playful. The skin plays and pauses the Web Animation as the badge enters and leaves the screen.
4.5:1 on its fill in every palette and themecontrastThe chip's text is the raised surface on the tone (or on-accent on accent). Every tone is already 4.5:1 against the surfaces, so the pair holds, and the tests check it for every palette and theme.

Accessibility

  • The badge is inline text. Nothing about it is focusable or interactive; if a status needs an action, put a button beside it.
  • The shape and the kolam are aria-hidden or content-free. The words are the only thing read.
  • Busy badges must say what is happening in words. Motion is decoration: none in quiet, none under reduced motion, paused off screen.
  • Every tone's text is 4.5:1 or more on every surface in warm, and on the tone's own fill in playful (tested for Susegad and Casa, light and dark).

Credit

The kolam flower is a small four-petal pulli kolam, the dot-grid form drawn at thresholds across South India. Tier: shared practice with local forms, used here as a small ornament only.

<sg-badge> is a word or two of status: Paid, Draft, Overdue, Saving. The text is the meaning; a shape per tone backs it up; colour comes last.

Use

<link rel="stylesheet" href="susegad/components/badge/badge.css">
<script type="module" src="susegad/components/badge/badge.js"></script>

<p>Your booking is <sg-badge tone="success">Confirmed</sg-badge>.</p>
<sg-badge tone="info" busy>Saving</sg-badge>

A server can swap the words (htmx hx-swap="innerHTML") or the tone; the badge re-fits its outline and re-detects the script.

Attributes

AttributeValuesDefault
toneneutral, accent, success, warning, danger, infoneutral
busyboolean: the thing is still happeningabsent
seedany string, for the warm outlinethe text
registerquiet, warm, playfulinherited
ToneShapeUse it for
neutralringarchived, counts, facts
accentdiamondnew, featured, direct
successtickpaid, confirmed, done
warningtriangle with a bardue soon, peak season, needs a look
dangercrossfailed, overdue, declined
infocircled idraft, returning guest, checking

Registers

LookWhen busy
quiettext colour, the tone's shape, a hairline rulenothing moves; the words say it
warmthe tone's ink, a hand-inked outline drawn twicethe shape breathes slowly
playfula chip of the tone, words in the page colour, a kolam flower on the cornerthe flower turns

Reduced motion keeps every register still. Busy motion pauses when the badge is off screen.

Accessibility

  • Inline text, never focusable. If a status needs an action, put a button next to it.
  • Do not rely on the tone: "Failed" in a red badge still says "Failed".
  • Busy badges must say in words what is happening ("Checking payment", not only a turning flower).
  • Contrast: warm text is 4.5:1 or more on every surface; the playful chip's text is 4.5:1 or more on its own fill, in every palette and theme (tested).
  • Devanagari and Kannada badges get more line height, so matras are not clipped.

Budget

FileBytes
badge.js + badge.core.js (behaviour)7.4 KB of 12 KB
skins/quiet.js0.2 KB
skins/warm.js2.1 KB
skins/playful.js1.3 KB

Nothing runs per frame except a busy badge's single Web Animation in warm or playful.