Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by eblairmckee
Edit on GitHub

BadgeGroup

A composable component for displaying a group of badges with overflow handling and "+N more" pattern.

Installation

bash
npx shadcn@latest add @redpanda/badge-group
bash
pnpm dlx shadcn@latest add @redpanda/badge-group
bash
yarn dlx shadcn@latest add @redpanda/badge-group
bash
bunx shadcn@latest add @redpanda/badge-group
bash
nubx shadcn@latest add @redpanda/badge-group
bash
aube dlx shadcn@latest add @redpanda/badge-group

Usage

The BadgeGroup component displays an explicit collection of items with automatic overflow handling. When there are more items than the maxVisible limit, excess items are collapsed into a “+N” badge. Pass a renderOverflowContent function to enable a tooltip on the overflow badge.

tsx
import { Badge } from '@/components/redpanda-ui/badge';import { BadgeGroup } from '@/components/redpanda-ui/badge-group';

Each item requires a unique, nonempty domain id, its rendered content, and a nonempty plain-text textValue. IDs identify items across deletion and reordering; mutable labels and array positions are not identity. JSX children are no longer accepted. Extra domain fields are inferred and preserved in the typed overflow callback.

Hidden items also have a permanent screen-reader description built from textValue; the overflow button references that description before the visual tooltip opens. renderOverflowContent remains supplementary and is rendered only once. Use wrapping or a visible detail surface when every item must be visually available on touch devices.

Basic Usage

tsx
// Shows: [React] [TypeScript] [Tailwind CSS] [+2]<BadgeGroup  maxVisible={3}  items={[    {      id: 'React',      textValue: 'React',      content: <Badge>React</Badge>,    },    {      id: 'TypeScript',      textValue: 'TypeScript',      content: <Badge>TypeScript</Badge>,    },    {      id: 'Tailwind CSS',      textValue: 'Tailwind CSS',      content: <Badge>Tailwind CSS</Badge>,    },    {      id: 'Next.js',      textValue: 'Next.js',      content: <Badge>Next.js</Badge>,    },    {      id: 'Node.js',      textValue: 'Node.js',      content: <Badge>Node.js</Badge>,    },  ]}/>

Props

Prop Type Default Description
items readonly BadgeGroupItem[] — Items with stable id, content, and plain-text textValue
maxVisible number 3 Nonnegative integer maximum of visible items
size 'sm' | 'md' | 'lg' 'sm' Size of the overflow badge
tone BadgeTone - Semantic color (tone) for the “+N” overflow badge
variant BadgeEmphasis 'subtle' Emphasis for the “+N” overflow badge
gap 'none' | 'xs' | 'sm' | 'md' | 'lg' 'sm' Gap between badges
wrap boolean false Allow badges to wrap to multiple lines
renderOverflowContent (overflow: readonly Item[]) => ReactNode - Custom render for overflow tooltip. If omitted, no tooltip is shown.

Examples

With Different Variants

tsx
<BadgeGroup  maxVisible={4}  items={[    {      id: 'Active',      textValue: 'Active',      content: (        <Badge tone="success" variant="subtle">          Active        </Badge>      ),    },    {      id: 'Pending',      textValue: 'Pending',      content: (        <Badge tone="warning" variant="subtle">          Pending        </Badge>      ),    },    {      id: 'In Review',      textValue: 'In Review',      content: (        <Badge tone="informative" variant="subtle">          In Review        </Badge>      ),    },    {      id: 'Archived',      textValue: 'Archived',      content: (        <Badge tone="default" variant="subtle">          Archived        </Badge>      ),    },  ]}/>

Custom Overflow Tooltip

tsx
<BadgeGroup  maxVisible={2}  renderOverflowContent={(overflow) => (    <div className="flex flex-col gap-1">{overflow.map((item) => item.textValue).join(', ')}</div>  )}  items={[    {      id: 'React',      textValue: 'React',      content: <Badge>React</Badge>,    },    {      id: 'TypeScript',      textValue: 'TypeScript',      content: <Badge>TypeScript</Badge>,    },    {      id: 'Tailwind CSS',      textValue: 'Tailwind CSS',      content: <Badge>Tailwind CSS</Badge>,    },    {      id: 'Next.js',      textValue: 'Next.js',      content: <Badge>Next.js</Badge>,    },  ]}/>

Wrapping Enabled

For cases where you want all badges visible:

tsx
<BadgeGroup  wrap  items={[    {      id: 'React',      textValue: 'React',      content: <Badge>React</Badge>,    },    {      id: 'TypeScript',      textValue: 'TypeScript',      content: <Badge>TypeScript</Badge>,    },    {      id: 'Tailwind CSS',      textValue: 'Tailwind CSS',      content: <Badge>Tailwind CSS</Badge>,    },  ]}/>

In ListView

BadgeGroup works well in the ListViewIntermediary slot:

tsx
<ListView>  <ListViewStart title="Model Name" />  <ListViewIntermediary>    <BadgeGroup      maxVisible={2}      items={[        {          id: 'React',          textValue: 'React',          content: <Badge size="sm">React</Badge>,        },        {          id: 'TypeScript',          textValue: 'TypeScript',          content: <Badge size="sm">TypeScript</Badge>,        },        {          id: 'Tailwind',          textValue: 'Tailwind',          content: <Badge size="sm">Tailwind</Badge>,        },      ]}    />  </ListViewIntermediary>  <ListViewEnd>    <Button>Configure</Button>  </ListViewEnd></ListView>

In ListCard

BadgeGroup also fits naturally in ListCardBody:

tsx
<ListCard>  <ListCardHeader>Model Name</ListCardHeader>  <ListCardBody>    <ListCardDescription>Description text...</ListCardDescription>    <BadgeGroup      maxVisible={3}      items={[        {          id: 'React',          textValue: 'React',          content: <Badge size="sm">React</Badge>,        },        {          id: 'TypeScript',          textValue: 'TypeScript',          content: <Badge size="sm">TypeScript</Badge>,        },        {          id: 'Tailwind',          textValue: 'Tailwind',          content: <Badge size="sm">Tailwind</Badge>,        },      ]}    />  </ListCardBody></ListCard>

Demo

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • minorv0.3.0Add theme-provider component to the registry with documentation and tests. Includes playground type improvements (export RegistryItem, remove as-const boilerplate) and docs site dark mode border color fix.#109
See full history →

Last updated on

Was this page helpful?