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

Dot Group

A positioning container that pins indicator dots to the corners of content elements, with optional overflow handling and standalone stacking mode.

Installation

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

Usage

tsx
import { DotGroup } from '@/components/redpanda-ui/dot-group';import { Badge } from '@/components/redpanda-ui/badge';
{  /* Position dots on content */}<DotGroup  content={    <Badge tone="default" variant="subtle">      kafka    </Badge>  }  size="sm"  items={[    {      id: 'errors',      kind: 'status',      variant: 'destructive',    },    {      id: 'warnings',      kind: 'status',      variant: 'warning',    },  ]}/>;
{  /* Standalone stacking (no content) */}<DotGroup  size="sm"  items={[    {      id: 'errors',      kind: 'status',      variant: 'destructive',    },    {      id: 'warnings',      kind: 'status',      variant: 'warning',    },  ]}/>;

Descriptors use caller-owned, nonempty, unique IDs. Editing a count or changing order retains that indicator’s DOM node; changing its ID intentionally replaces it. label supplies an optional complete accessible name, including the count when relevant. The group owns size, overlap, and stack order; standalone StatusDot and CountDot remain unchanged.

When to use

Use DotGroup when:

  • Positioning indicator dots on a badge, avatar, or other content element
  • Displaying multiple status or count indicators that need compact stacking
  • You need to truncate many indicators to a visible subset (maxVisible prop)

Don’t use DotGroup when:

  • You only have a single indicator without content to attach it to (use StatusDot or CountDot directly)
  • You need a label alongside the indicator (use StatusBadge)
  • On a StatusBadge — it already composes StatusDot internally

Modes

Content positioning mode

When content is provided, DotGroup wraps the content in a relative container and positions the dots at the specified corner. This is the primary use case.

tsx
<DotGroup  content={    <Badge tone="default" variant="subtle">      Service    </Badge>  }  size="sm"  items={[    {      id: 'errors',      kind: 'status',      variant: 'destructive',    },  ]}/>

Standalone mode

Without content, DotGroup renders dots in a horizontal stack with overlapping negative margins. This is useful for inline indicator groups.

tsx
<DotGroup  size="sm"  items={[    {      id: 'errors',      kind: 'status',      variant: 'destructive',    },    {      id: 'warnings',      kind: 'status',      variant: 'warning',    },  ]}/>

Pattern: Same-type grouping

Prefer same-type indicators for consistent visual weight. Items are explicit status or count descriptors with stable IDs. Status-only groups support every dot size; any count indicator requires sm, md, or lg. Arbitrary JSX children and implicit prop injection are no longer supported.

tsx
// StatusDot group<DotGroup content={<Badge tone="default" variant="subtle">kafka</Badge>} size="sm" items={[    {        id: "errors",        kind: "status",        variant: "destructive"    },    {        id: "warnings",        kind: "status",        variant: "warning"    }]}/>
// CountDot group<DotGroup content={<Badge tone="default" variant="subtle">broker-0</Badge>} size="sm" items={[    {        id: "warnings",        kind: "count",        count: 5,        variant: "warning"    },    {        id: "errors",        kind: "count",        count: 2,        variant: "destructive"    }]}/>

Pattern: Overflow

When maxVisible is set and items exceed it, DotGroup renders the first N dots followed by a + icon signaling that more indicators exist. The icon sizes and contrasts automatically with the dots.

tsx
<DotGroup  content={    <Badge tone="default" variant="subtle">      events    </Badge>  }  maxVisible={3}  size="sm"  items={[    {      id: 'errors',      kind: 'status',      variant: 'destructive',    },    {      id: 'warnings',      kind: 'status',      variant: 'warning',    },    {      id: 'information',      kind: 'status',      variant: 'informative',    },    {      id: 'healthy',      kind: 'status',      variant: 'success',    },    {      id: 'disabled',      kind: 'status',      variant: 'disabled',    },  ]}/>;{  /* Shows the first 3 dots + overflow indicator */}

Anatomy

plaintext
Content positioning mode┌──────────────────────────────────┐│                        [●][●]   │  ← absolute positioned at corner│  Badge Label                    ││                                 │└──────────────────────────────────┘
Standalone mode[●][●][●]  ← overlapping inline indicators with ring separation

API Reference

DotGroup

A status descriptor has id, kind: 'status', optional variant, pulsing, and label. A count descriptor has id, kind: 'count', required count, and optional variant, max, and label. label is the complete accessible indicator name; unlabelled dots remain decorative. Group IDs must be nonempty and unique. maxVisible must be a nonnegative integer.

Prop Type Default Description
items readonly DotGroupItem[] — Explicit status/count descriptors with stable IDs
content ReactNode? — Element to position dots relative to
position "top-right" | "top-left" | "bottom-right" | "bottom-left" | "top" | "bottom" | "left" | "right" "top-right" Position for dots when using content mode (corners or edge-centers)
size "xxs" | "xs" | "sm" | "md" | "lg" "md" Controls owned dot size and overlap; count items require sm or larger
maxVisible number? — Maximum dots to show; overflow renders a + icon
testId string? — Test ID for visual regression testing
className string? — Additional CSS classes

Credits

  • Follows the overlapping stack pattern from AvatarGroup but simplified for indicator use cases.
  • Designed to compose with StatusDot and CountDot.

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?