A mail inbox with folders, unread state, multi-select with bulk actions, search, a reading pane, empty states and keyboard navigation.
A three-pane inbox: folders, the conversation list and the message. It follows its own width, not the window's: at tablet width the folders move into a select above the list, and on a phone the list and the message take turns on screen. Try it at each width with the toggle above the preview.
minimal · light · #3fa34d
Inbox
8 conversations, 3 unread
↑↓ move · X select · Enter open
Brand guidelines, version 3
Design
MC
Marina Costamarina@lumen.studio · to me
9:41 AM
Hi! The new colour tokens and the type scale we agreed on Tuesday are in the shared folder, along with the logo lockups for dark backgrounds.
The main change from version 2 is the accent: we moved it one step darker so links pass 4.5:1 on the tinted cards. Could you check the checkout screens before Friday?
Unread state. Unread conversations have a bold sender and subject and a bar in the accent color. Opening one marks it as read; the folder counts update.
Selection. Each row has a checkbox, and the one above the list selects every visible row (it shows a dash when only some are). The toolbar acts on the selection: Archive, Delete and Mark as read or unread. In Archive and Trash, Archive becomes Move to Inbox.
Undo. Moving conversations shows a toast with an Undo button that puts them back where they were.
Search. The search box filters the current folder by sender, subject and preview as you type, ignoring accents ("julia" finds "Júlia"). When nothing matches, an empty state says so and offers to clear the search.
Reading pane. With room for both panes, the first conversation is open from the start, and archiving or deleting it opens the next one. The message shows its sender, date and body, with the same actions in a toolbar and a reply box that checks it isn't empty before sending.
Compose. Compose (in the folder column, or above the list on narrower screens) opens a new message in the reading pane; it checks the recipient's email and that the message isn't empty.
Empty folders. An empty Inbox says you're caught up; Archive and Trash say what ends up there.
The list uses a roving tab stop: Tab enters the list once, on the last row you were on. ↑ and ↓ move between rows, Home and End jump to the ends, X selects the focused row and Enter opens it. With a keyboard and room to spare, the keys are listed under the list and linked to it with aria-describedby; on touch screens and phones the hint is hidden. The focused row gets the skin's focus ring.
Unread rows start with a hidden "unread" so screen readers hear the state, not just the bold text. The open conversation has aria-current.
Each checkbox is named after its conversation ("Select Marina Costa: Brand guidelines, version 3"), and the icon buttons in the toolbars have names and tooltips.
When rows disappear (archived or deleted), focus moves to the folder heading instead of being lost. On a phone, opening a message moves focus to its subject, and Back returns it to the row.
The selection count and the toasts are announced through live regions.
The Code tab shows the whole screen as one file, with @camaleo/react and lucide-react as its only dependencies. Messages are fixed data and the folder of each one lives in local state; swap both for your API. The useWidth hook at the top is what lets the layout follow its own box, so it also works inside a resizable panel.