Skip to content
caliper ui docs

Components

Tag overflow

A row of tags that shows the first few and folds the rest into a "+N" count. Choosing the count opens the rest one after another in place, and "Show less" folds them back.

Free
pnpm dlx shadcn@latest add @caliper/tag-overflow

Accounts

Extra tags fold into a count.

  • Northwind Traders
    EnterpriseEURenewal Q1
  • Harbour & Co
    StartupMonthly
Installs components/ui/tag-overflow.tsxDepends on none beyond ReactMotion none in component source

When to use

Use it for

  • Table cells, cards and headers where a record can have many tags.
  • Filters and categories that must not take over a layout.

Skip it when

  • Tags people edit; use `TagInput`.
  • Two or three tags; just show them.

Decisions

Why it is built this way, so you know what to keep when you change your copy.

Behaviour

Opens in place
The extra tags appear where they belong, one after another, instead of in a popover that hides the row.

Usage

A disclosure
The count is a button that says how many it will show and whether it is open; focus stays on it.

Installation

terminal
pnpm dlx shadcn@latest add @caliper/tag-overflow

Adds its 3 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage

This is the code behind the preview above.

example.tsx
import { type ReactNode } from "react"
import { TagOverflow } from "@/components/ui/tag-overflow"

function Panel({ title, context, className = "max-w-md", children }: { title: string; context: string; className?: string; children: ReactNode }) {
  return (
    <section className={`grid w-full gap-5 rounded-overlay border border-border bg-background p-6 shadow-resting max-sm:p-4 ${className}`}>
      <div className="grid gap-1">
        <p className="font-medium">{title}</p>
        <p className="text-sm text-muted-foreground">{context}</p>
      </div>
      {children}
    </section>
  );
}

export function TagOverflowDemo() {
  return (
    <Panel title="Accounts" context="Extra tags fold into a count.">
      <ul className="grid gap-4 text-sm">
        <li className="grid gap-2">
          <span className="font-medium">Northwind Traders</span>
          <TagOverflow label="Northwind tags" tags={[{ label: "Enterprise", tone: "violet" }, { label: "EU", tone: "blue" }, { label: "Renewal Q1", tone: "amber" }, "SSO", "Priority support", "Annual", "Security review"]} />
        </li>
        <li className="grid gap-2">
          <span className="font-medium">Harbour & Co</span>
          <TagOverflow label="Harbour tags" max={2} tags={[{ label: "Startup", tone: "green" }, "Monthly", "Trial ended", "Referral"]} />
        </li>
      </ul>
    </Panel>
  );
}

API reference

TagOverflow

component

Also accepts the native props of its root element and a ref.

PropTypeDefaultDescription
label *string—Names the set, e.g. "Labels".
tags *(string | OverflowTag)[]—
maxnumber3Tags shown before the rest fold into a count.

Accessibility

It exposes group semantics, with aria-label and aria-expanded kept in step with state.

No custom key handling; Tab and the native activation keys do the work.

Motion

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.

All Surfaces examples