Installation
pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/badge.jsonInstalls to @/components/ui/badge.
Manual installation
Install the dependencies:
pnpm add @base-ui/react@^1.8.0 class-variance-authority@^0.7.1Copy the source into your project:
import { mergeProps } from '@base-ui/react/merge-props'
import { useRender } from '@base-ui/react/use-render'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const badgeVariants = cva(
'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!',
{
variants: {
variant: {
default: 'bg-muted text-foreground [a]:hover:bg-muted/80',
secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
destructive: 'bg-destructive-subtle text-destructive-subtle-foreground [a]:hover:bg-destructive-subtle/60',
info: 'bg-info-subtle text-info-subtle-foreground [a]:hover:bg-info-subtle/60',
success: 'bg-success-subtle text-success-subtle-foreground [a]:hover:bg-success-subtle/60',
warning: 'bg-warning-subtle text-warning-subtle-foreground [a]:hover:bg-warning-subtle/60',
outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
link: 'text-primary underline underline-offset-4',
},
},
defaultVariants: {
variant: 'default',
},
},
)
function Badge({
className,
variant = 'default',
render,
...props
}: useRender.ComponentProps<'span'> & VariantProps<typeof badgeVariants>) {
return useRender({
defaultTagName: 'span',
props: mergeProps<'span'>(
{
className: cn(badgeVariants({ variant }), className),
},
props,
),
render,
state: {
slot: 'badge',
variant,
},
})
}
export { Badge, badgeVariants }A versatile badge component for displaying short status descriptors, labels, or counts. Built with class-variance-authority for flexible styling and variants, it provides a consistent way to show metadata or status.
Features
- Nine visual variants:
default,secondary,destructive,info,success,warning,outline,ghost,link - Single compact size (20px high, pill shaped)
- Icon support with
data-icon="inline-start"/data-icon="inline-end"(icons are sized to 12px automatically) - Polymorphic rendering with the
renderprop (e.g. render as a link, with hover styles) - Exposes
data-slot="badge"anddata-variantfor styling hooks - Focus ring and
aria-invalidstyling
Usage
import { Badge } from '@/components/ui/badge'
import { BadgeCheck } from 'lucide-react'
// Basic usage
export function StatusBadge() {
return <Badge>Draft</Badge>
}
// With variants
export function VariantBadges() {
return (
<div className="flex gap-2">
<Badge variant="default">Draft</Badge>
<Badge variant="secondary">Submitted</Badge>
<Badge variant="destructive">Rejected</Badge>
<Badge variant="info">In review</Badge>
<Badge variant="success">Approved</Badge>
<Badge variant="warning">Awaiting documents</Badge>
<Badge variant="outline">Archived</Badge>
<Badge variant="ghost">Public record</Badge>
</div>
)
}
// With icon
export function SignedBadge() {
return (
<Badge variant="success">
<BadgeCheck data-icon="inline-start" />
Signed with BankID
</Badge>
)
}
// As link
export function CaseLink() {
return (
<Badge render={<a href="/cases/2026-04812" />} variant="link">
2026-04812
</Badge>
)
}Examples
Default
All Variants
Each variant with the kind of label it suits.
Case Status
Status badges in a case list: info for a case in progress, warning for one waiting on the applicant, success for
an approval and destructive for a rejection. Each status also has an icon and text, so it never relies on colour
alone.
<Badge variant="warning">
<TriangleAlertIcon data-icon="inline-start" />
Awaiting documents
</Badge>With Icons
Mark icons with data-icon so the badge tightens its padding on that side.
Counts
Use min-w-5 px-1 tabular-nums for numeric counters, here in a case inbox navigation.
As Link
With the render prop, the badge renders as another element, such as a button that removes a filter. Variants include
hover styles for anchors.
Props
variant- Visual style variant ('default' | 'secondary' | 'destructive' | 'info' | 'success' | 'warning' | 'outline' | 'ghost' | 'link', default'default')render- The element to render instead of aspan, e.g.render={<a href="…" />}className- Additional CSS classes- All HTML
spanattributes
badgeVariants is also exported for applying badge styles to other elements.
Variants
default- Muted background with foreground textsecondary- Muted, lower emphasis styledestructive- Soft tinted style for errors or failuresinfo- Soft primary tint for neutral progress, such as a case in reviewsuccess- Soft green tint for completed or approved stateswarning- Soft amber tint for states that need attention, such as missing documentsoutline- Bordered style with transparent backgroundghost- No background until hoveredlink- Underlined text link style
Accessibility
- Renders a
spanby default, so it does not add semantics - Status is also carried by the text, and ideally an icon, never by colour alone:
info,success,warninganddestructiveadd tone, the label says what it means - The status variants keep at least 4.5:1 text contrast on their tint in light and dark mode, in both themes
- When rendering as a link with
render, the badge keeps the anchor semantics and focus ring
Best Practices
-
Content Guidelines:
- Keep text concise
- Use clear language
- Consider localization
-
Visual Design:
- Use
destructiveonly for errors - Use
success,warningandinfofor status, and keep one meaning per variant across an app - Prefer
secondaryoroutlinefor neutral metadata
- Use
-
Icon Usage:
- Use relevant icons
- Mark them with
data-iconfor correct spacing
Related Components
- Button
- Label