--- ## Badge Compact label for status, categories, counters, and notifications. Badge props are a discriminated union. The pure-indicator dot — spelled canonically as `purpose="dot"` or via the deprecated `variant="dot"` — forbids `children` / `counter` / `removable` / `interactive` / `onRemove` at the type level, while the label arms (`filled` / `outlined` / `soft`; `purpose` `status` / `tag` / `counter` / `chip`) accept the full surface. A badge with an `onclick` handler is announced as a `button` and joins the tab order. A static one takes its role from `purpose`: `status` and `dot` are a `status` live region; `tag`, `counter` and `chip` carry no role and render a plain span, so a tag inside a link is a label and not a live region; without `purpose` it stays a `status`. Override via `role`. Its accessible name is always the visible label; a removable badge's ✕ control names itself ("Remove badge"). Takes no `href`. A link that should look like a Badge is an `` with `badgeVariants({ … }).base()` on it — the recipe in `urbicon primer` under "A link that looks like a button". **Import:** `import { Badge } from '@urbicon-ui/blocks';` ### Examples ```svelte Active 5 removeTag('react')}>React ``` ```svelte
5
``` ### Variants - intent: danger, neutral, primary, secondary, success, warning (default: primary) - variant: dot, filled, outlined, soft (default: filled) - size: lg, md, sm, xs (default: md) - border: true (default: false) - counter: true (default: false) - disabled: true (default: false) - interactive: true (default: false) - placement: bottom, bottom-end, bottom-start, left, right, top, top-end, top-start - pulse: true (default: false) - removable: true (default: false) - tier: commit, modify (default: commit) ### Api | Prop | Type | Required | Default | Description | | --- | --- | :---: | --- | --- | | purpose | `'dot'` | yes | | The canonical dot spelling — forces the pure-indicator look regardless of `variant`. For the label roles use `status` / `tag` / `counter` / `chip` (their own arm). | | border | `boolean` | no | | Add a ring outline in the page background color — useful to visually separate overlapping or positioned badges from their parent. | | children | `Snippet` | no | | Badge content (text, icons, numbers). | | class | `string` | no | | Extra classes merged onto the root element. In the same Tailwind bucket `class` wins over the `slotClasses` entry for the element it lands on. Presets and provider defaults sit below both. | | counter | `boolean` | no | | Display as a compact pill for numeric counts (tightens padding, tabular-nums). Keeps the pre-`purpose` ARIA default with the rest of the low-level props: a badge driven by this boolean stays a `"status"` live region, where `purpose="counter"` carries no role. A count that must be announced when it changes sets `role="status"` explicitly. | | disabled | `boolean` | no | | Visually disable the badge (reduced opacity, no pointer events). | | interactive | `boolean` | no | | Enable the interactive look (pointer cursor, hover/press scale, mint). Automatically enabled when `onclick` is provided — and only the handler makes the badge a tab stop with Enter/Space activation; `interactive` alone never creates a focus stop that answers no key. | | mint | `MintProp` | no | 'none' | Micro-interaction preset applied to the badge. Only applies while interactive (`purpose="chip"`, `interactive`, or `onclick`) and not disabled. | | onclick | `(event: MouseEvent) => void` | no | | Click handler. Makes the badge operable: interactive styles, a tab stop, Enter/Space activation and `role="button"`. | | onHover | `(hovered: boolean) => void` | no | | Called when the hover state changes. | | onRemove | `() => void` | no | | Fired when the remove button is clicked (only when `removable` is true). | | placement | `BadgePlacement` | no | | Anchor the badge absolutely within a `position: relative` parent. | | preset | `string` | no | | Apply a named preset registered via ``. Prefer this over `class` overrides when the requested look falls outside the semantic intent palette — presets keep hover/active/dark-mode logic coherent and make the custom look reusable across the project. | | pulse | `boolean` | no | | Add a pulsing animation to draw attention (e.g. for live indicators). Stilled under `prefers-reduced-motion`. | | removable | `boolean` | no | | Show a remove (×) button. | | role | `'status' | 'alert' | 'button'` | no | | ARIA role. Derived from `purpose` when unset: `status` and `dot` render `"status"` — a polite live region, right for a state marker; `tag`, `counter` and `chip` render no role — a category, a count or a filter chip announces nothing when it changes, so it stays a plain `span`: a label inside a link rather than a live region inside one. A badge with an `onclick` handler (when not `disabled`) is a `"button"` whatever its purpose, so assistive tech announces its activation semantics; `purpose="chip"` or `interactive` alone change only the look — without a handler there is nothing to activate, so no button is announced and the badge stays outside the tab order. Without `purpose` a static badge keeps `"status"`, and so does the deprecated `counter` boolean. Set explicitly to override: `"status"` for a count that must be announced when it changes, `"alert"` for a time-sensitive notification. An explicit value always wins over the derived default. | | slotClasses | `Partial>` | no | | Per-slot class overrides merged with tv styles. In the same Tailwind bucket `class` wins over the `slotClasses` entry for the element it lands on. Presets and provider defaults sit below both. | | unstyled | `boolean` | no | | Remove all default tv classes. | | variant | `'filled' | 'outlined' | 'soft'` | no | 'filled' | Visual variant. `dot` renders a pure indicator (content hidden); the label variants accept the full surface. | | intent | `'danger' | 'neutral' | 'primary' | 'secondary' | 'success' | 'warning'` | no | primary | Controls the color theme and semantic meaning of the Badge. Affects the overall appearance and user perception. Available options: danger, neutral, primary, and 3 more. | | size | `'lg' | 'md' | 'sm' | 'xs'` | no | md | Controls the dimensions, padding, and text size of the Badge. Affects the component's physical footprint. Available options: lg, md, sm, xs. | | tier | `'commit' | 'modify'` | no | commit | Selects the semantic radius tier of the Badge — the shape family it belongs to (`--radius-commit`/`-modify`/`-contain`/`-bridge`). Shape is retuned per family in your theme, so this picks the family rather than a pixel value. Available options: commit, modify. | ### Types ```ts type BadgeProps = BadgeDotByPurposeProps | BadgeDotProps | BadgeStandardProps ``` ```ts type BadgePlacement = (typeof PLACEMENT_VALUES)[number] ``` ```ts type MintProp = | MintName | { name: MintName; config?: MintConfig & Record } | Array | Array }> ``` ```ts type MintName = BuiltinMintName | 'none' | (string & {}) ``` ```ts interface MintConfig { /** * `hover` and `focus` hold the effect while the pointer/visible focus stays * on the element; `click` and `load` run it once. */ trigger?: 'hover' | 'click' | 'focus' | 'load'; /** * Effect duration in ms. Written as an inline per-effect custom property * (`--blocks-mint--duration`), so the CSS transition/animation * actually runs at this speed; unset, the theme duration tokens apply. */ duration?: number; /** Delay in ms before the effect applies. */ delay?: number; /** * CSS easing for the effect (`--blocks-mint--easing` inline); * unset, the per-effect theme default applies. */ easing?: string; disabled?: boolean; } ``` ```ts type BuiltinMintName = (typeof BUILTIN_MINT_NAMES)[number] ``` ### Slots (slotClasses keys) `base`, `content`, `removeButton`, `removeIcon`