Skip to main content
Gremorie
Display

Badge

Compact label for status, counts, and tags. Eight variants, optional asChild for link-style badges.

Overview

Badge is the static label primitive: a small, rounded pill for statuses ("Active", "Pending"), counts ("12", "99+"), tags ("AI", "Beta"), or category markers. It renders as a <span> by default - or any element via asChild - and is intentionally non-interactive. For selectable chips, reach for ToggleGroup; for clickable badges that link somewhere, use asChild to compose with an <a> or Link component.

Eight variants ship by default: default (filled primary), secondary, destructive, warning, success, outline, ghost, and link. The three status fills - destructive (error), warning (attention), success (ok) - each clear WCAG AA 4.5:1 in light and dark mode. Hover states only apply when Badge is rendered as an anchor (via the [a&]:hover:... selector pattern), so the static variants stay truly static.

Preview

DefaultSecondaryOutlineDestructiveWarningSuccess
'use client';import { Badge } from '@gremorie/rx-display';export function BadgePreview() {  return (    <div className="flex flex-wrap items-center gap-2">      <Badge>Default</Badge>      <Badge variant="secondary">Secondary</Badge>      <Badge variant="outline">Outline</Badge>      <Badge variant="destructive">Destructive</Badge>      <Badge variant="warning">Warning</Badge>      <Badge variant="success">Success</Badge>    </div>  );}

Anatomy

Badge   rounded, bordered pill wrapping text and/or a leading size-3 icon

Installation

bash npx gremorie@latest add rx-badge
bash pnpm dlx gremorie@latest add rx-badge
bash yarn dlx gremorie@latest add rx-badge
bash bunx --bun gremorie@latest add rx-badge

Usage

import { Badge } from "@gremorie/rx-display";

export function Example() {
  return (
    <div className="flex flex-wrap items-center gap-2">
      <Badge>Default</Badge>
      <Badge variant="secondary">Secondary</Badge>
      <Badge variant="outline">Outline</Badge>
      <Badge variant="destructive">Destructive</Badge>
      <Badge variant="warning">Warning</Badge>
      <Badge variant="success">Success</Badge>
    </div>
  );
}
npx gremorie@latest add ng-badge

Prerequisite

Angular components emit Tailwind utility classes and ship no compiled CSS. Without the setup below in src/styles.css the component mounts but renders completely unstyled. Requires Tailwind CSS v4.

@import 'tailwindcss';@import '@gremorie/tokens/theme.css';/* Required. Tailwind v4 skips node_modules by default, so without this line   the components' utility classes never reach your compiled CSS and every   Gremorie component renders unstyled. */@source '../node_modules/@gremorie';

The @source line is required: Tailwind v4 skips node_modules by default. Adjust the relative path if your stylesheet is not at src/styles.css. Full setup in Installation.

import { Component } from '@angular/core';
import { Badge } from '@gremorie/ng-display';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [Badge],
  template: `
    <div class="flex flex-wrap items-center gap-2">
      <gr-badge>Default</gr-badge>
      <gr-badge variant="secondary">Secondary</gr-badge>
      <gr-badge variant="outline">Outline</gr-badge>
      <gr-badge variant="destructive">Destructive</gr-badge>
      <gr-badge variant="warning">Warning</gr-badge>
      <gr-badge variant="success">Success</gr-badge>
    </div>
  `,
})
export class ExampleComponent {}

API

<Badge>

PropTypeDefaultDescription
variant"default" | "secondary" | "destructive" | "warning" | "success" | "outline" | "ghost" | "link""default"Visual style. default is filled primary; destructive / warning / success are the status fills (error, attention, ok); outline shows only a border; ghost is invisible until rendered as an anchor; link styles as inline text.
asChildbooleanfalseWhen true, renders the immediate child via Radix Slot and merges all classes onto it. Use to wrap an <a> or framework Link.
classNamestring-Extra classes merged via cn.

All other span props are forwarded.

The badgeVariants CVA function is also exported, so you can compose Badge styles onto a custom element without using Badge itself:

import { badgeVariants } from '@gremorie/rx-display';

<a href="/docs" className={badgeVariants({ variant: 'outline' })}>
  Docs
</a>;

Composition

Badge is a leaf component - it has no sub-parts. The two composition levers are:

  1. variant to switch the visual treatment.
  2. asChild to render Badge styles onto a different element (typically an anchor or framework link).

Icons compose naturally: drop an SVG inside Badge and the variant CSS handles sizing ([&>svg]:size-3).

Variations

All variants

DefaultSecondaryDestructiveWarningSuccessOutlineGhostLink
'use client';import { Badge } from '@gremorie/rx-display';export function BadgeVariantsPreview() {  return (    <div className="flex flex-wrap items-center gap-2">      <Badge>Default</Badge>      <Badge variant="secondary">Secondary</Badge>      <Badge variant="destructive">Destructive</Badge>      <Badge variant="warning">Warning</Badge>      <Badge variant="success">Success</Badge>      <Badge variant="outline">Outline</Badge>      <Badge variant="ghost">Ghost</Badge>      <Badge variant="link">Link</Badge>    </div>  );}

All eight variants side by side: default (filled primary), secondary, destructive, warning, success, outline, ghost, and link. ghost reads as plain text until rendered as an anchor.

Status indicator

ActiveExpiringFailedDraft
'use client';import { Badge } from '@gremorie/rx-display';import { AlertCircleIcon, AlertTriangleIcon, CheckIcon } from 'lucide-react';export function BadgeStatusPreview() {  return (    <div className="flex flex-wrap items-center gap-2">      <Badge variant="success">        <CheckIcon />        Active      </Badge>      <Badge variant="warning">        <AlertTriangleIcon />        Expiring      </Badge>      <Badge variant="destructive">        <AlertCircleIcon />        Failed      </Badge>      <Badge variant="outline">Draft</Badge>    </div>  );}

The three status fills map to the three outcomes: success for ok, warning for attention, destructive for error. Pair each one with an icon and text so the status reads clearly without relying on color alone. Icons inside Badge size automatically via [&>svg]:size-3.

'use client';import { Badge } from '@gremorie/rx-display';export function BadgeLinkPreview() {  return (    <Badge asChild variant="outline">      <a href="#docs">Read the docs</a>    </Badge>  );}

Hover styles activate automatically when Badge renders as an anchor - that is what the [a&]:hover:... selectors do internally.

Count badge

Inbox12Notifications99+
'use client';import { Badge } from '@gremorie/rx-display';export function BadgeCountPreview() {  return (    <div className="flex items-center gap-2">      <span className="text-sm">Inbox</span>      <Badge>12</Badge>      <span className="text-sm">Notifications</span>      <Badge variant="destructive">99+</Badge>    </div>  );}

Accessibility

  • Static by default: Badge renders a <span> and has no role. Screen readers announce its text content as inline text.
  • Status updates: when a Badge's content changes dynamically (e.g. a count that updates live), wrap a parent in an aria-live="polite" region so assistive tech announces the change.
  • Color-only meaning is not enough: use icons or text in addition to the variant color so users who can't perceive color still get the message ("Active" plus a check icon, not just a green pill).
  • Status fill contrast: destructive, warning and success are token pairs (--warning / --warning-foreground) tuned so the text clears WCAG AA 4.5:1 at badge size in both light and dark mode. If you override the fill with a custom class, re-check the contrast yourself.
  • Interactive badges: when rendering as an anchor via asChild, the anchor's native semantics apply - focus, Enter to activate, screen reader announcement as a link.
  • aria-invalid: Badge styles aria-invalid={true} automatically with destructive border and ring - useful when Badge is part of a form field.
  • Card - frequent host for Badge via CardAction.
  • Avatar - pairs with AvatarBadge for presence dots.
  • Alert - for non-inline status that needs more room.

On this page