caliper uidocs

Item

Free

A generic row: media, title, description, meta and an action. It uses the data table's row spacing and its hover and selected fills.

Installs components/ui/item.tsxDepends on @radix-ui/react-slotMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/item.json
A very long file name that should truncate instead of pushing the action off the row.pdf
Uploaded by Tom · 2.4 MB

When to use #

Use it for

  • Settings lists, search results, files and people.
  • The row inside a menu or a panel.

Skip it when

  • Tabular data with columns to compare; use the data table.
  • A row with a link and a button side by side; make the row the link.

Decisions #

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

Behaviour

Long text is cut, the action stays
Title and description truncate to one line so the action never moves.

Styling

The table's row, in black and white
Padding and hover match the data table. The selected row is a neutral fill with a 2px ink edge, so a list never turns orange or brown.

Usage

A row that goes somewhere is one link
Use asChild with a link. A link and a button in the same row give two tab stops for one idea.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/item.json

Adds its 2 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. It is built from Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemMeta and ItemTitle.

example.tsx
import { Bell, ChevronRight, FileText, Link2 } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemMeta, ItemTitle } from "@/components/ui/item"

export function ItemDemo() {
  return (
    <div className="grid w-full max-w-md gap-6">
      <ItemGroup>
        <Item asChild>
          <a href="#forma">
            <ItemMedia>FS</ItemMedia>
            <ItemContent>
              <ItemTitle>Forma Studio</ItemTitle>
              <ItemDescription>14 projects · Owner</ItemDescription>
            </ItemContent>
            <ItemMeta>Active now</ItemMeta>
            <ChevronRight data-mirror="" aria-hidden="true" className="size-4 text-muted-foreground" />
          </a>
        </Item>
        <Item asChild current>
          <a href="#ines">
            <ItemMedia round>IR</ItemMedia>
            <ItemContent>
              <ItemTitle>Inês Duarte</ItemTitle>
              <ItemDescription>ines@halden.app · Customer team</ItemDescription>
            </ItemContent>
            <Badge>Selected</Badge>
          </a>
        </Item>
        <Item asChild>
          <a href="#notifications">
            <ItemMedia><Bell aria-hidden="true" /></ItemMedia>
            <ItemContent>
              <ItemTitle>Notifications</ItemTitle>
              <ItemDescription>Email on invoices, push for approvals</ItemDescription>
            </ItemContent>
            <ChevronRight data-mirror="" aria-hidden="true" className="size-4 text-muted-foreground" />
          </a>
        </Item>
        <Item disabled>
          <ItemMedia><Link2 aria-hidden="true" /></ItemMedia>
          <ItemContent>
            <ItemTitle>Webhooks</ItemTitle>
            <ItemDescription>Available on the Team plan</ItemDescription>
          </ItemContent>
        </Item>
      </ItemGroup>
      <ItemGroup separate>
        <Item>
          <ItemMedia><FileText aria-hidden="true" /></ItemMedia>
          <ItemContent>
            <ItemTitle>A very long file name that should truncate instead of pushing the action off the row.pdf</ItemTitle>
            <ItemDescription>Uploaded by Tom · 2.4 MB</ItemDescription>
          </ItemContent>
          <Button size="sm" variant="secondary">Download</Button>
        </Item>
      </ItemGroup>
    </div>
  );
}

API reference #

Item

component

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

PropTypeDefaultDescription
asChildboolean—Render the row as its child, such as a link: `<Item asChild><a href="…">…</a></Item>`.
currentboolean—The row for the current page or selection.
disabledboolean—

ItemContent

component

No props of its own; it accepts the native props of its root element.

ItemDescription

component

No props of its own; it accepts the native props of its root element.

ItemGroup

component

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

PropTypeDefault
separateboolean—

ItemMedia

component

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

PropTypeDefault
roundboolean—

ItemMeta

component

No props of its own; it accepts the native props of its root element.

ItemTitle

component

No props of its own; it accepts the native props of its root element.

Accessibility #

It exposes list semantics, with aria-current and aria-disabled 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.