Item list

A card-per-row list with a leading icon, auto-derived columns, inline actions, and click-through navigation.

Name
Team member
Date
Amount
Chrome
Web Browser
Ann Wong
10 Apr 2017
$88,904.92
Slack
Communication
Georgie Bryant
09 Apr 2017
$61,636.03
Spotify
Music
Todd Murphy
07 Jun 2017
$15,970.97
Instagram
Social Media
Ollie Lambert
15 Sep 2017
$46,926.03
Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/item-list.json
Usage
Pass a `data` array of dicts. Columns are derived from the keys (minus reserved keys like `icon`, `title`, `actions`, `href`); pass `columns` to reorder, relabel, align, or custom-render.
TSImport
import { ItemList, type ItemListRow } from "@/components/ui/item-list";
TSExample
import { ItemList, type ItemListRow } from "@/components/ui/item-list";
import { GlobeIcon } from "lucide-react";

const data: ItemListRow[] = [
  {
    icon: GlobeIcon,
    title: "Chrome",
    subtitle: "Web Browser",
    member: "Ann Wong",
    amount: "$88,904.92",
    href: "/apps/chrome",
  },
];

export function Example() {
  // Columns auto-derive from the keys (member, amount); pass `columns` to
  // reorder / relabel / align / custom-render.
  return <ItemList data={data} />;
}
Composition
Anatomy of the ItemList primitive.
ItemList (props)                              // flat, card-per-row list
├── data: ItemListRow[]                       // each row is a dict
│   ├── icon? | image?                        // leading visual
│   ├── iconClassName?                        // e.g. "bg-transparent" for bare brand marks
│   ├── title / subtitle?                     // leading text
│   ├── [key]: ReactNode                      // any other key → a data column (auto)
│   ├── actions?: { icon, label, onClick }[]  // animate-ui icon buttons
│   └── href? | onNavigate?                   // trailing chevron navigation
├── variant?: "card" | "flat"                 // card rows (default) or hairline rows
├── columns?: ItemListColumn[]                // optional: reorder / relabel / align / render
├── nameHeader?  (default "Name")
├── sortable?                                 // click a header: asc → desc → unsorted
├── sort? / defaultSort? / onSortChange?      // controlled or uncontrolled sort
├── nameSortValue?                            // what the name column sorts by
└── hideHeader? / emptyState? / getRowId?

Row = <Card> surface
├── Leading cell — icon|image + title + subtitle
├── Data columns — value rendered as-is (drop in Badge / Select / Input to edit inline)
├── Action cluster — animated Lucide icons, animate on hover
└── Chevron — navigates via href (<a>) or onNavigate
Default
App-directory style: a leading icon + title/subtitle, data columns, a status indicator, animate-ui icon actions, and a chevron that navigates. Columns are reordered/aligned via `columns`.
Name
Team member
Date
Amount
Chrome
Web Browser
Ann Wong
10 Apr 2017
$88,904.92
Slack
Communication
Georgie Bryant
09 Apr 2017
$61,636.03
Spotify
Music
Todd Murphy
07 Jun 2017
$15,970.97
Instagram
Social Media
Ollie Lambert
15 Sep 2017
$46,926.03
Flat
`variant="flat"` — same inputs, file-browser look: no cards, hairline dividers, wide 16:10 thumbnails or bordered file-icon tiles, and muted data columns. Actions match the card variant. Drop a `Badge` into `title` for inline tags.
FUSE Branding Redesign.png
FUSE Branding Redesign
4.2 MB
Oct 5
FUSE Social Media Graphics.psd
Social Media Graphics
121.8 MB
Oct 5
Signage - 15 x 10 v2.aiCurrent
Signage
3.1 MB
Oct 5
MAIN TITLE.psdCurrent
Signage
6.2 MB
Oct 5
Grain.png
Signage
9.7 MB
Oct 5
15x10 Fabric Pop-Up Display.pdf
Signage
911 KB
Oct 5
FUSE Postcard 6x4.jpg
Postcard
3.7 MB
Oct 5
Fuse 2025 - Concept 1.jpg
Event Design
1.7 MB
Oct 5
Inline editing
A cell value can be any node — drop a `Badge`, `Select`, or `Input` into a column and wire its `onChange` to your own state. The list stays uncontrolled.
Name
Tier
Plan
Seats
Northpoint
Atlanta, GA
scale
Redeemer
New York, NY
growth
Cornerstone
Austin, TX
starter
Auto columns
Pass just `data` — columns are inferred from the dict keys (minus reserved keys). No actions or navigation.
Name
Region
Uptime
Marketing site
Production
us-east-1
99.98%
Docs
Production
eu-west-2
99.95%
Status page
Edge
global
100%
API Reference
Props for the flat `<ItemList>` component plus the row, column, and action shapes.

ItemList

PropTypeDefaultDescription
dataItemListRow[]—Rows to render. Each is a dict; non-reserved keys become data columns automatically.
variant"card" | "flat""card"`card` wraps each row in a Card. `flat` drops the cards for hairline-split rows, wide 16:10 thumbnails, and muted columns.
columnsItemListColumn[]—Optional override — reorder, relabel, align, set width, or custom-render columns. Omit to auto-derive from keys.
nameHeaderReactNode"Name"Header label for the leading (icon + title) column.
hideHeaderbooleanfalseHide the uppercase column-label header row.
sortablebooleanfalseMake every column header a button that sorts the rows: ascending, then descending, then back to the order of `data`. Blank values always go last. A column can opt out with its own `sortable: false`.
sort{ key: string; direction: "asc" | "desc" } | null—Controlled sort. `key` is a column key, or `"title"` for the name column; `null` is unsorted.
defaultSort{ key: string; direction: "asc" | "desc" } | null—The starting sort when `sort` is not passed.
onSortChange(sort) => void—Called with the new sort (or `null`) when a header is clicked.
nameSortValue(row) => string | number | boolean | Date | null—What the name column sorts by. Defaults to `title` when it is text.
getRowId(row, index) => string—Stable row key. Falls back to `row.id` then the index.
emptyStateReactNode—Rendered in place of the list when `data` is empty.
aria-labelstring—Accessibility label for the list.
classNamestring—Extra wrapper classes.

ItemListRow

PropTypeDefaultDescription
idstring | number—Stable id (else `getRowId`, else the index).
iconComponentType<{ className?: string }>—Leading icon (use this OR `image`).
iconClassNamestring—Classes merged onto the icon's chip. Pass `bg-transparent` for marks that bring their own shape (brand logos).
imagestring—Leading image URL (use this OR `icon`).
imageAltstring—Alt text for `image`.
titleReactNode—Primary label in the leading cell.
subtitleReactNode—Secondary muted label under the title.
actionsItemListAction[]—Animated icon-action buttons rendered before the chevron.
hrefstring—Navigate here when the chevron is clicked (renders an `<a>`).
targetHTMLAttributeAnchorTarget—Anchor target for `href`.
onNavigate(row) => void—Alternative to `href` — called when the chevron is clicked.
[key]ReactNode—Any other key becomes a data column. The value may be any node — text, a Badge, a Select, an Input, etc.

ItemListColumn

PropTypeDefaultDescription
keystring—Row key this column reads.
headerReactNode—Header label. Defaults to a humanized version of `key`.
align"start" | "center" | "end""start"Text alignment for the column.
widthstring | number—Track width (number = px). Defaults to a flexible `1fr`.
render(value, row) => ReactNode—Custom cell renderer. Without it the raw value renders as-is.
classNamestring—Extra classes on the cell.
sortableboolean—Override the list's `sortable` for this column.
sortValue(row) => string | number | boolean | Date | null—What this column sorts by. Text, numbers, booleans and Dates sort as themselves; give a column of nodes (a Badge, a formatted date) its value here.

ItemListAction

PropTypeDefaultDescription
iconAnimatedIconComponent—Animated (motion) Lucide icon — e.g. `FoldersIcon` from `@/components/ui/folders`. Plays its animation on hover.
labelstring—Accessible label + tooltip.
onClick(e) => void—Fires when the action is clicked.
disabledboolean—Disables the action.