KQ-1304 · MAIL/INBOX

Mail Inbox

An inbox built for triage: a row's face follows the finger 1:1 and reveals its action from the edge it leaves, archive on a green pigment and snooze on an amber one, arming with a pop on snap at the commit line; a release past it (or a throw, by projection) runs the row out on glide with its release velocity before its height closes, and a short one springs home on snap. Selecting a thread slides a batch toolbar down over the header on snap with a rolling count, opening one fades its unread dot and glides its messages open under the row (or into a reading pane when the inbox is wide), and every archive leaves an Undo toast that lands on recoil. j and k move, x selects, Enter opens, e archives, b snoozes, s stars, u toggles unread, z undoes and Escape backs out.

KQ-1304 · MAIL/INBOX

Inbox

4 unread

j and k move between threads, x selects, Enter opens, e archives, b snoozes, s stars, u marks unread, z undoes. Swipe a row right or left for its actions.

4 unread · swipe right to archive, left to snooze

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/mail-inbox

Props

swipe
"full" | "reveal" | "off"
default "full"
How a swipe commits: past 42% of the row, resting open on its action (a long swipe still commits), or not at all, leaving the hover tools and keys.
density
"compact" | "cozy" | "roomy"
default "cozy"
Row height and type size: single-line compact rows, cozy, or roomy with larger avatars.
preview
number
default 1
Lines of message preview under the subject, 0 to 2.
threads / defaultThreads
MailThread[]
default defaultMailThreads
Every thread in every folder, each a subject and its messages oldest first. Controlled or uncontrolled.
onThreadsChange
(threads: MailThread[]) => void
default —
Fires from the swipe, key or button that changed the threads, with all of them.
folder / defaultFolder
"inbox" | "snoozed" | "archive"
default "inbox"
The folder on screen. Controlled or uncontrolled.
onFolderChange
(folder: MailFolder) => void
default —
Fires when a folder is chosen on the rail or the folder chips.
selected / defaultSelected
string[]
default []
Selected thread ids. A selection brings in the batch toolbar.
onSelectedChange
(ids: string[]) => void
default —
Fires from the checkbox, x, select-all or batch action that changed the selection.
open / defaultOpen
string | null
default null
The open thread: expanded under its row, or in the reading pane once the inbox is 68rem wide.
onOpenChange
(id: string | null) => void
default —
Fires when a thread opens or closes.
swipeActions
{ right: MailAction | null; left: MailAction | null }
default { right: "archive", left: "snooze" }
Which action each swipe direction runs; null leaves that direction rubber-banding. In the archive or snoozed folder the action that would send a thread where it is moves it back to the inbox.
now
Date | number
default defaultMailNow
The moment times are read against (09:12, Yesterday, Tue, 25 Sep). Never read from the clock during render.
zoneOffset
number
default 0
Minutes east of UTC that times are shown in, so the server and the browser draw the same inbox.
snoozeUntil
(now: number) => number
default —
When a snooze ends, from now. Defaults to the next day at 08:00.
account
MailPerson
default —
Whose inbox it is: shown on the rail, and their messages read as "me".
label
string
default "Mail"
The inbox's accessible name.
status
"ready" | "loading" | "error"
default "ready"
Loading draws placeholder rows; error offers Retry.
onRetry
() => void
default —
Retry was pressed on the error state.
onArchive
(ids: string[]) => void
default —
Threads were sent to the archive, by swipe, key, hover tool or batch.
onSnooze
(ids: string[], until: number) => void
default —
Threads were snoozed, and until when.
onRestore
(ids: string[]) => void
default —
Threads were moved back to the inbox from the archive or a snooze.
onReadChange
(ids: string[], unread: boolean) => void
default —
Threads were marked read by opening them, or toggled with u or the mail tool.
onStarChange
(id: string, starred: boolean) => void
default —
A thread was starred or unstarred.
onReply
(threadId: string) => void
default —
Reply was pressed on an open thread.
onCompose
() => void
default —
Compose was pressed on the rail.
onUndo
(ids: string[]) => void
default —
The last archive or snooze was undone from the toast or with z.
sound
boolean
default false
Play a pop when a swipe arms, a pick or a star lands, and a swish as rows leave. Off unless asked for.
disabled
boolean
default false
Makes the whole inbox inert.
className
string
default —
Classes for the root; it is 560px tall by default and lays out by its own width.