shadimage
indiacn
uibadgesource: ok · refreshed

Badge

Compact label for status, counts, or categories. 9 themes × 3 variants × 3 sizes × 2 shapes.

npx shadcn add "https://indiacn.in/r/badge.json"
free

Where it goes

stats

Interaction

animated-counter

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
class-variance-authority

Registry dependencies

https://indiacn.in/r/theme.jsonhttps://indiacn.in/r/typography.json

Files1 · source cached 10/8/2026, 4:09:25 AM

components/ui/badge.tsx
import { cva, type VariantProps } from 'class-variance-authority';
import { ComponentProps } from 'react';

import { Label2 } from '@/components/ui/typography';
import { cn } from '@/lib/utils';

/* UX4G label-3 type scale: 11px/16px, 0.5px tracking. Padding stays em-based so badges scale with context. */
const BADGE_VARIANTS = cva(
  'inline-flex items-center justify-center whitespace-nowrap align-baseline text-center transition-colors focus:outline-none',
  {
    variants: {
      theme: {
        primary:
          'text-primary [--badge-bg:var(--color-primary)] [--badge-fg:var(--color-primary-foreground)] [--badge-bg-tonal:var(--color-primary-100)] [--badge-border-color:var(--color-primary)] [--badge-text-color:var(--color-primary)]',
        secondary:
          'text-secondary [--badge-bg:var(--color-secondary)] [--badge-fg:var(--color-secondary-foreground)] [--badge-bg-tonal:var(--color-secondary-100)] [--badge-border-color:var(--color-secondary)] [--badge-text-color:var(--color-secondary)]',
        success:
          'text-success [--badge-bg:var(--color-success)] [--badge-fg:var(--color-success-foreground)] [--badge-bg-tonal:var(--color-success-100)] [--badge-border-color:var(--color-success)] [--badge-text-color:var(--color-success)]',
        danger:
          'text-danger [--badge-bg:var(--color-danger)] [--badge-fg:var(--color-danger-foreground)] [--badge-bg-tonal:var(--color-danger-100)] [--badge-border-color:var(--color-danger)] [--badge-text-color:var(--color-danger)]',
        warning:
          'text-warning [--badge-bg:var(--color-warning)] [--badge-fg:var(--color-warning-foreground)] [--badge-bg-tonal:var(--color-warning-100)] [--badge-border-color:var(--color-warning)] [--badge-text-color:var(--color-warning)]',
        info: 'text-info [--badge-bg:var(--color-info)] [--badge-fg:var(--color-info-foreground)] [--badge-bg-tonal:var(--color-info-100)] [--badge-border-color:var(--color-info)] [--badge-text-color:var(--color-info)]',
        neutral:
          'text-neutral [--badge-bg:var(--color-neutral)] [--badge-bg-tonal:var(--color-neutral-100)] [--badge-border-color:var(--color-neutral)] [--badge-text-color:var(--color-neutral)]',
        light:
          'text-neutral [--badge-bg:var(--color-neutral-50)] [--badge-bg-tonal:var(--color-neutral-50)] [--badge-border-color:var(--color-neutral-200)] [--badge-text-color:var(--color-neutral)]',
        dark: 'text-neutral-0 [--badge-bg:var(--color-neutral)] [--badge-bg-tonal:var(--color-neutral-900)] [--badge-border-color:var(--color-neutral)] [--badge-text-color:var(--color-neutral-0)]',
      },
      variant: {
        filled:
          'bg-(--badge-bg) text-[var(--badge-fg,var(--color-neutral-0))] border border-transparent',
        outlined: 'bg-transparent border border-(--badge-border-color) text-(--badge-text-color)',
        tonal: 'bg-(--badge-bg-tonal) text-(--badge-text-color) border border-transparent',
      },
      size: {
        sm: 'px-[0.4em] py-[0.2em] text-[10px] leading-[14px]',
        md: 'px-[0.61em] py-[0.35em] text-[11px] leading-4',
        lg: 'px-[0.8em] py-[0.45em] text-xs leading-4',
      },
      shape: {
        default: 'rounded-[0.375rem]',
        pill: 'rounded-full',
      },
    },
    compoundVariants: [
      { theme: 'light', variant: 'filled', className: 'text-neutral' },
      { theme: 'dark', variant: 'filled', className: 'text-neutral-0' },
    ],
    defaultVariants: {
      theme: 'primary',
      variant: 'filled',
      size: 'md',
      shape: 'default',
    },
  },
);

interface IBadgeProps
  extends Omit<ComponentProps<'span'>, 'color'>,
    VariantProps<typeof BADGE_VARIANTS> {}

/**
 * A compact badge component for displaying status, counts, or category labels.
 * Matches the UX4G 2.0 Badge specification.
 *
 * Supports:
 * - Visual variants: filled, outlined, tonal
 * - Theme colors: primary, secondary, success, danger, warning, info, neutral, light, dark
 * - Sizes: sm, md, lg
 * - Shapes: default (rounded), pill (fully rounded)
 */
function Badge({ className, variant, theme, size, children, shape, ...props }: IBadgeProps) {
  return (
    <Label2 className={cn(BADGE_VARIANTS({ variant, theme, size, shape, className }))} {...props}>
      {children}
    </Label2>
  );
}

export { Badge, BADGE_VARIANTS };

More from indiacn

Browse all components in this library →