Badge
Small labels in four styles, with status tones, a pulsing dot and a small size for counts.
Variants
Details
What Badge brings along, read from the registry and the source.
- Category
- Data display
- Area
- Elements
- Variants
- 4
- Version
- 1.1.0 · since 1.0.0
- File
- components/ui/badge.tsx
- Brings along
- utils
- npm packages
- None
- Languages
- Texts come through props
- Studio
- Adjust in code
- Build with AI
- Over MCP in Claude, Cursor, Copilot and Codex
Props
The BadgeProps interface from components/ui/badge.tsx, with the comments from the code. Also takes every prop of React.HTMLAttributes<HTMLSpanElement>.
variantoptionalBadgeVariantdefaultoutlinesoftsolid
dotoptionalbooleanA pulsing point in front
toneoptionalBadgeToneaccentneutralsuccesswarningdangerinfo
Status meaning: success, warning, danger, info or neutral. Default the accent.
sizeoptional'sm' | 'md'sm for counts in tabs and navigation, md the default
childrenrequiredReact.ReactNode
Accessibility
Read from the source of the component.
- Needs no client state. The server writes it in full, so it reads without JavaScript too.
Motion
- Brings animations of its own, calmly timed and without wobble.
- With reduced motion (prefers-reduced-motion) it stays still. 1 places in the code switch motion off then.
Source
The file aiw add puts into your project. From then on it is yours.
Show the file, 65 lines
'use client';
import { cn } from '@/lib/kit';
export type BadgeVariant = 'default' | 'outline' | 'soft' | 'solid';
/** Meaning of a status badge. Colors soft and outline badges and the dot of a default badge, solid stays on the accent. */
export type BadgeTone = 'accent' | 'neutral' | 'success' | 'warning' | 'danger' | 'info';
const VARIANT: Record<BadgeVariant, string> = {
default: 'bg-muted text-foreground',
outline: 'border border-border-strong text-muted-foreground',
soft: 'bg-[color-mix(in_oklab,var(--primary)_12%,transparent)] text-[color-mix(in_oklab,var(--primary)_80%,var(--foreground))]',
solid: 'bg-primary text-primary-foreground',
};
const TONE: Record<Exclude<BadgeTone, 'accent'>, { color: string; text: string }> = {
neutral: { color: 'var(--muted-foreground)', text: 'text-muted-foreground' },
success: { color: 'var(--success)', text: 'text-success-foreground' },
warning: { color: 'var(--warning)', text: 'text-warning-foreground' },
danger: { color: 'var(--destructive)', text: 'text-destructive' },
info: { color: 'var(--info)', text: 'text-info' },
};
const TONED: Partial<Record<BadgeVariant, string>> = {
soft: 'bg-[color-mix(in_oklab,var(--badge)_15%,transparent)]',
outline: 'border border-[color-mix(in_oklab,var(--badge)_45%,var(--border))]',
};
const SIZE = {
sm: 'h-5 gap-1 px-2 text-[11px] tabular-nums',
md: 'h-6 gap-1.5 px-2.5 text-xs',
};
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
variant?: BadgeVariant;
/** A pulsing point in front */
dot?: boolean;
/** Status meaning: success, warning, danger, info or neutral. Default the accent. */
tone?: BadgeTone;
/** sm for counts in tabs and navigation, md the default */
size?: 'sm' | 'md';
className?: string;
children: React.ReactNode;
}
/** Small label for status, category or "New". With dot it gets a pulsing point in front, with tone a status color. */
export function Badge({ variant = 'default', dot, tone, size = 'md', className, style, children, ...rest }: BadgeProps) {
const t = tone && tone !== 'accent' ? TONE[tone] : undefined;
const toned = t && TONED[variant];
return (
<span
{...rest}
style={t ? ({ '--badge': t.color, ...style } as React.CSSProperties) : style}
className={cn('inline-flex items-center whitespace-nowrap rounded-full font-medium', SIZE[size], toned ? cn(toned, t.text) : VARIANT[variant], className)}
>
{dot && (
<span className={cn('relative flex size-1.5', t && !toned && variant === 'default' && t.text)} aria-hidden>
<span className="absolute inset-0 animate-kit-pulse rounded-full bg-current motion-reduce:animate-none" />
<span className="relative size-1.5 rounded-full bg-current" />
</span>
)}
{children}
</span>
);
}Frequent questions
How do I install Badge?
With aiw add @ai-website/badge. The command puts components/ui/badge.tsx into your project, the code is yours from then on. It needs no further npm packages.
Which variants does Badge have?
4 variants, Styles, status and counts, Status in a list, Counts in navigation and On cards. You pick one with the variant prop, for example variant="soft".
Can an AI assistant build with Badge?
Yes. Through the MCP server of the aiw CLI, Claude, Cursor, GitHub Copilot, Windsurf, Codex and Gemini find Badge with aiw_components and install it with aiw_add @ai-website/badge. Name the variant in your prompt, for example variant="soft", and the assistant writes your content straight into the props.