Badge
Displays a small status indicator, label, or tag.
Installation
npx vayu-ui init # one time onlynpx vayu-ui add badgenpx vayu-ui add -t badge # with test case needsUsage
Badge Component
A flexible, accessible Badge component. Supports variants, interactive modes (onClick), and dismissible states. Compliant with WCAG 2.2 target sizes.
Variants
BrandMutedSuccessWarningDestructiveInfo
Sizes
Small (24px)Medium (28px)Large (32px)
Interactive
Click to trigger an alert.
Dismissible
Click the X to remove tags.
ReactTailwindTypescriptNext.js
Interactive + Dismissible
Click text to trigger filter, click X to remove.
// Variants
<Badge variant="brand">Brand</Badge>
<Badge variant="muted">Muted</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="info">Info</Badge>
// Sizes
<Badge size="sm">Small</Badge>
<Badge size="md">Medium</Badge>
<Badge size="lg">Large</Badge>
// Interactive
<Badge variant="info" onClick={() => alert("Clicked")}>
Click Me
</Badge>
// Dismissible
<Badge variant="muted" onDismiss={() => {}} dismissLabel="Remove tag">
Removable Tag
</Badge>
// Interactive + Dismissible
<Badge
variant="brand"
onClick={() => alert("Filter applied")}
onDismiss={() => {}}
>
Filter
</Badge>Anatomy
<Badge variant="brand" size="md" onClick={() => {}} onDismiss={() => {}} dismissLabel="Remove">
Badge Content
</Badge>| Element | Description |
|---|---|
| Root | Container element (span by default, button when onClick is provided) |
| Dismiss Button | Close icon button, rendered only when onDismiss is provided |
Accessibility
Badge follows WCAG 2.2 Level AA guidelines.
Keyboard Support
| Pattern | Key | Behavior |
|---|---|---|
| Interactive badge | Tab | Moves focus to the badge |
| Interactive badge | Enter | Activates the onClick handler |
| Interactive badge | Space | Activates the onClick handler |
| Dismiss button | Tab | Moves focus between main action and dismiss |
| Dismiss button | Enter | Triggers the onDismiss handler |
ARIA Attributes
| Element | Role | Attributes |
|---|---|---|
| Interactive badge | button | type="button" |
| Dismiss button | button | aria-label="{dismissLabel}" |
| Split-button container | group | role="group" |
Focus Behavior
- Focus ring uses the
focusdesign token (ring-2 ring-focus) - Focus offset adapts to dark mode (
ring-offset-canvas) - Dismiss button uses inset focus ring to stay within bounds
Screen reader behavior
| State | Announcement |
|---|---|
| Static badge | Read as inline text (no role) |
| Interactive badge | Announced as a button with the badge text as its name |
| Dismissible badge | Badge text followed by a "Remove" button (or custom dismissLabel) |
| Interactive + Dismissible | Announced as a group containing two buttons: the main action and the dismiss action |
Component Folder Structure
Badge/
├── Badge.tsx # UI + logic
├── types.ts # TypeScript types
├── index.ts # Public exports
└── README.md # Internal notesProps
Badge
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'brand' | 'muted' | 'warning' | 'success' | 'destructive' | 'info' | 'brand' | Visual style variant |
size | 'sm' | 'md' | 'lg' | 'md' | Size of the badge |
as | 'span' | 'div' | 'a' | - | Forces a specific HTML tag |
onClick | () => void | - | Makes badge interactive (renders as button) |
onDismiss | () => void | - | Adds a dismiss button |
dismissLabel | string | 'Remove' | Accessible label for the dismiss button |
className | string | - | Additional CSS classes |
Behavior Patterns
| Pattern | Props | Rendered Element |
|---|---|---|
| Static | Default | <span> |
| Interactive | onClick | <button type="button"> |
| Dismissible | onDismiss | <span> containing a close button |
| Interactive + Dismissible | onClick + onDismiss | <span role="group"> with two sibling <button> elements |