Item
A row with media, a title, a description, and actions, in three sizes, for lists that are not tables.
Item is a single row built from slots: ItemMedia for an icon or an image, ItemContent with
an ItemTitle and an ItemDescription, and ItemActions at the end. ItemGroup stacks rows
and ItemSeparator divides them, and ItemHeader and ItemFooter add a full-width line above
or below a row. It has three sizes, default, sm, and dense, and
Record list builds its rows on dense.
Create, assign, jump to a record.
Usage
import {
Item,
ItemContent,
ItemDescription,
ItemMedia,
ItemTitle,
} from '@/components/ui/item';
<Item size="dense">
<ItemMedia variant="icon">{/* icon */}</ItemMedia>
<ItemContent>
<ItemTitle>Command palette</ItemTitle>
<ItemDescription>Create, assign, jump.</ItemDescription>
</ItemContent>
</Item>Item holds no data, so you map your own records into rows and keep what a row does when it is
pressed. Rows inside an ItemGroup are a list.
Three sizes
default is p-4 with a 16px gap and sm is px-4 py-3 with a 10px gap. Both wrap when they
run out of room. dense is px-3 py-1.5 with an 8px gap and does not wrap, so it holds one line
of text, for a long list of records. ItemDescription clamps to two lines. The variant is the
surface: default is transparent, outline adds a border, and muted is a sunken tint.
A title with a line under it.
A title with a line under it.
Media
ItemMedia is a bare slot by default. variant="icon" draws a 32px bordered tile on the sunken
surface with a 16px icon, and variant="image" draws a 40px rounded image box that crops with
object-cover. When the row has a description, the media aligns to the top of the text and not
the middle.
As a link or a button
asChild renders the row as its one child, so a row can be a link. A row rendered as a link gets
the fill background on hover, and any row that can take focus shows a 2px focus ring on
:focus-visible.
<Item asChild size="sm">
<a href="/settings/billing">
<ItemContent>
<ItemTitle>Billing</ItemTitle>
</ItemContent>
</a>
</Item>A plain Item is a <div>, which is not focusable, so it has no focus ring and no hover state
until you make it interactive. Only a link gets the hover fill, so give a button row its own
hover:bg-fill, as Record list does.
Props
Item takes every <div> attribute, plus these. The other parts take the attributes of their
element.
| Prop | Type | Default | What it does |
|---|---|---|---|
variant | "default" | "outline" | "muted" | "default" | The surface: transparent, bordered, or a sunken tint. |
size | "default" | "sm" | "dense" | "default" | The row's padding and gap. dense is one line and does not wrap. |
asChild | boolean | false | Renders its one child with the row's styling, for a link or a button. |
ItemMedia takes variant, "default" \| "icon" \| "image", and "default" is the default.
Accessibility
ItemGroupis arole="list", and each Item in it arole="listitem", so a screen reader announces the count. An Item withasChildkeeps its link or button role inside a list item of its own. A row outside a group has no role, and aroleyou pass replaces either, likerole="option"in a listbox, as Record list does.ItemTitleis a<div>and not a heading, andItemDescriptionis a<p>.- With
asChild, the child keeps its own role, so an<a>is a link and a<button>is a button, and Enter and Space work as they do natively. Put the whole row's name in its title, since the link's name is all of its text. - A focusable row shows a 2px ring on
:focus-visiblein the ring color. The row has no 44px touch minimum, so give an interactive row the height you need. - Color changes on hover take 100ms and stop under reduced motion.
ItemSeparatoris decorative by default, so a screen reader skips it.
When to use something else
- Record list for records grouped into buckets
with the keyboard moving between rows and Enter opening one. It is built on Item at
dense, so reach for Item when you only need rows and not the grouping or the keys. The Issues example uses it. - Table when rows have columns to compare. An Item has slots, not columns.
- Card for a framed group of content, where an Item is one line of a list. Interactive card when that frame is the thing you open, with media above or beside the text.
- Menu or Command when the rows are choices that run an action and close.
Install
shadcn add @gesso/item