InboxList
<InboxList> is the canonical two-pane inbox layout — selectable rows on the left, preview of the selected item on the right. Built-in j / k row navigation, Enter to open, e to archive, ⌘Enter to mark-read-and-next.
When to use
- Triage queues — review requests, notifications, audit reports.
- Anywhere “long list of things, look at one at a time” is the workflow.
Don’t use InboxList for: full lists where the user needs to scan many at once (DataTable), kanban-style stage management (BoardView), or single-pane lists.
Default
- New review requestAcme moved a deal…
- Build failedCI failure on dev-v2
- Doc updateddesign-system 04-components.md
- Comment on PRLooks good — ship it.
New review request
Acme moved a deal…
<InboxList<Item> items={items} selectedId={selectedId} onSelect={(id, item) => setSelectedId(id)} onArchive={(item) => archive(item.id)} onOpen={(item) => router.push(`/items/${item.id}`)} renderRow={(item, state) => ( <div className={state.unread ? 'font-medium' : 'text-muted-foreground'}> {item.title} </div> )} renderPreview={(item) => <ItemPreview item={item} />}/>API
| Prop | Type | Default | Description |
|---|---|---|---|
items * | T[] | — | List rows. Must extend { id, unread? }. |
selectedId | string | null | — | Controlled selected id. Defaults to the first item. |
onSelect | (id: string, item: T) => void | — | Fires on click or j/k. |
onArchive | (item: T) => void | — | Fires on `e` keystroke. |
onOpen | (item: T) => void | — | Fires on Enter. |
onMarkReadAndNext | (item: T) => void | — | Fires on ⌘Enter. |
renderRow * | (item, state) => ReactNode | — | Row renderer. State has { selected, unread }. |
renderPreview * | (item: T) => ReactNode | — | Preview renderer for the selected item. |
header | ReactNode | — | Above the list — typically title + unread count + archive-all. |
emptyState | ReactNode | — | Empty list. Defaults to a friendly "all caught up". |
emptyPreview | ReactNode | — | Shown when no item is selected. |
listWidth | "narrow" | "wide" | "narrow" | narrow=360px, wide=420px. |
Design guidelines
✓ Do
- Match the keyboard contract. j/k for next/prev, Enter to open, e to archive — these are sacred.
- Keep row renderers small — title + 1-line preview + timestamp. The preview pane is the detail.
- Default-select the first item so the preview pane isn't empty on load.
✗ Don't
- Use InboxList for static reference content. The keyboard overhead doesn't earn its keep.
- Render long preview content without an internal scroll — wrap it in ScrollArea.
Accessibility
- Rows are
<button role="option">insiderole="listbox". - The preview is
<aside>linked viaaria-controls. - Keyboard: j/k next/prev, Enter open, e archive.
Related
Timeline— Common preview content for activity-style inboxes.PropertyList— Common preview content for entity-style inboxes.DataTable— When the user needs to scan many at once instead.