Badge
A small status or count indicator. Attach it to any element as a floating pip, drop it inline next to text, or render it standalone — all three modes share the same class surface.
The examples are organised by layer: the class reference is the standalone
@oriui/css layer, and the Framework API is the @oriui/vue component. Every
example is live — flip its code between HTML (the standalone classes, also your htmx / Astro / Svelte /
plain-HTML usage), Vue; HTML is the default.
Classes
A badge is a block class plus single-class token utilities — one class repoints one token; no base
class is needed. The Vue props in Framework API map 1:1 to these. Two layout
modifiers (ori-badge_dot, ori-badge_floating) and the wrapper class (ori-badge-anchor)
complete the floating pattern.
| Class | Type | Description |
|---|---|---|
ori-badge | Block | Required base class. Defaults baked in: fill variant, primary color, rounded radius. |
ori-variant_* | Style | fill · tonal · outline · text · plain |
ori-color_* | Color | primary · secondary · success · warn · danger · info · surface · background |
ori-size-radius_* | Radius | zero · xs · sm · md · lg · xl · rounded |
ori-badge_dot | Layout | collapses the badge to a small filled circle; content is hidden |
ori-badge_floating | Layout | positions the badge in the top-end corner of its anchor wrapper |
ori-badge-anchor | Wrapper | position:relative wrapper required for floating badges |
Variants
Five visual styles, driven by the ori-variant_* single-class token.
<span class="ori-badge">Fill</span>
<!-- swap the variant: ori-variant_tonal / _outline / _text / _plain -->
<span class="ori-badge ori-variant_tonal">Tonal</span>
Colors
All semantic roles. The badge inherits the shared ori-color_* token, so variant × color compose freely.
<span class="ori-badge ori-color_danger">danger</span>
Variant × color compose freely — e.g. a tonal success badge or an outline danger badge:
<span class="ori-badge ori-variant_tonal ori-color_success">Approved</span>
<span class="ori-badge ori-variant_outline ori-color_danger">Error</span>
Radius
From zero (square) to the default rounded (pill).
<span class="ori-badge ori-size-radius_zero">zero</span> <span class="ori-badge">rounded</span>
Count & max
Pass a number to content. Set max to cap the display value — any number exceeding max renders
as {max}+.
<span class="ori-badge">5</span>
<!-- cap manually in your template when not using Vue -->
<span class="ori-badge ori-color_danger">99+</span>
Dot
dot collapses the badge to a small filled circle. Content is hidden; it is always decorative
(aria-hidden="true") unless you provide a label.
<!-- dot is always aria-hidden unless a label is provided -->
<span class="ori-badge ori-badge_dot ori-color_danger" aria-hidden="true"></span>
Floating
The badge floats over wrapped content — floating needs the badge to wrap an anchor. In Vue, pass
the anchor into the default slot and add the floating prop (without a default slot floating has
nothing to position against and is ignored). In HTML, wrap the anchor in ori-badge-anchor and add
ori-badge_floating to the badge itself.
<!-- wrap anchor content in ori-badge-anchor, add ori-badge_floating to the badge -->
<span class="ori-badge-anchor">
<button class="ori-button ori-variant_tonal ori-color_primary ori-size-radius_rounded">Inbox</button>
<span class="ori-badge ori-badge_floating ori-color_danger" aria-label="3 unread">3</span>
</span>
Common patterns
A notification bell, an avatar with a status pip, and a tab bar with unread counts.
<!-- notification bell -->
<span class="ori-badge-anchor">
<button class="ori-button …" aria-label="Notifications"><!-- bell icon --></button>
<span class="ori-badge ori-badge_floating ori-color_danger" aria-label="12 unread notifications">12</span>
</span>
<!-- status dot on avatar -->
<span class="ori-badge-anchor">
<div class="ori-avatar …"><!-- avatar --></div>
<span class="ori-badge ori-badge_dot ori-badge_floating ori-color_success" aria-label="Online"></span>
</span>
<!-- inline tab counter -->
<span style="display: inline-flex; align-items: center; gap: 0.5rem">
Messages
<span class="ori-badge ori-variant_tonal">5</span>
</span>
Accessibility
The accessibility contract holds across every layer — the standalone classes and the Vue component render the same attributes.
- A badge with visible text content (
content) conveys that text to assistive technology directly. - A pure dot badge — or an empty badge with no
label— is markedaria-hidden="true"because it carries no information for screen readers. - Supply a
labelwhenever the badge conveys meaning that a sighted user can read but a screen reader cannot (e.g. a dot meaning "online", or a floating count with no textual fallback nearby). - A floating count that visually annotates an already-labeled control (e.g. "Inbox (3 unread)")
should carry
aria-labelon the badge element or be hidden witharia-hidden="true"if the parent label already includes the count. - The badge is a
<span>— it has no interactive role and no keyboard contract of its own. When a badge and its anchor together form an interactive control, apply focus management and ARIA to the outer interactive element.
| Attribute | Condition | Value |
|---|---|---|
aria-hidden="true" | dot with no label, or empty badge with no label | "true" |
aria-label | label prop is set | label value |
Framework API
The props, events, and slots of the Vue component. The standalone CSS layer has no component API — its surface is the classes above. (Svelte bindings are planned.)
Props
| Prop | Type | Default | Description |
|---|---|---|---|
color | ThemeColor | 'primary' | Semantic color role: primary · secondary · success · warn · danger · info · surface · background. |
content | string | number | — | Text or number to display. Numbers are capped to max+ when max is set. |
dot | boolean | false | Collapses the badge to a small filled circle; content is hidden. |
floating | boolean | false | Positions the badge in the top-end corner of the default-slot anchor (requires a default slot child). |
label | string | — | Accessible name (aria-label). Required for dot badges or empty badges that convey meaning to sighted users. |
max | number | — | When content is a number and exceeds max, the display value is capped to {max}+. |
radius | RadiusSize | 'rounded' | Corner radius: zero · xs · sm · md · lg · xl · rounded. |
variant | Variant | 'fill' | Visual style: fill · tonal · outline · text · plain. |
Events & attributes
OriBadge declares no custom events. It sets inheritAttrs: false and applies v-bind="$attrs"
directly to the inner .ori-badge element — so id, class, data-*, and event listeners always
land on the badge element regardless of whether a default slot (the anchor wrapper) is present.
Slots
| Slot | Description |
|---|---|
default | The element the badge floats over. When provided, the component wraps both the slot content and the badge in an ori-badge-anchor span. When absent, the badge renders standalone. |
content | Custom badge content, replacing the capped content value ({max}+) that renders by default. Only renders when not a dot. A badge that uses this slot is kept in the a11y tree (not decorative). |