rapidUI

Badge

Small status or count label with semantic color variants.

Installation

pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/badge.json

Installs to @/components/ui/badge.

Manual installation

Install the dependencies:

pnpm add @base-ui/react@^1.8.0 class-variance-authority@^0.7.1

Copy the source into your project:

components/ui/badge.tsx
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 render prop (e.g. render as a link, with hover styles)
  • Exposes data-slot="badge" and data-variant for styling hooks
  • Focus ring and aria-invalid styling

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.

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 a span, e.g. render={<a href="…" />}
  • className - Additional CSS classes
  • All HTML span attributes

badgeVariants is also exported for applying badge styles to other elements.

Variants

  • default - Muted background with foreground text
  • secondary - Muted, lower emphasis style
  • destructive - Soft tinted style for errors or failures
  • info - Soft primary tint for neutral progress, such as a case in review
  • success - Soft green tint for completed or approved states
  • warning - Soft amber tint for states that need attention, such as missing documents
  • outline - Bordered style with transparent background
  • ghost - No background until hovered
  • link - Underlined text link style

Accessibility

  • Renders a span by default, so it does not add semantics
  • Status is also carried by the text, and ideally an icon, never by colour alone: info, success, warning and destructive add 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

  1. Content Guidelines:

    • Keep text concise
    • Use clear language
    • Consider localization
  2. Visual Design:

    • Use destructive only for errors
    • Use success, warning and info for status, and keep one meaning per variant across an app
    • Prefer secondary or outline for neutral metadata
  3. Icon Usage:

    • Use relevant icons
    • Mark them with data-icon for correct spacing
  • Button
  • Label