Skip to main content
A tab is a filtered view of the same message stream. A feed groups tabs, so the inbox can offer several sets of them. Start where your app already is: a tab is a saved query, not a separate mailbox. Nothing routes a message to a tab at send time. Every tab reads the same messages and shows the ones its filter matches, which is why one message can appear in several tabs at once.
The Courier Inbox header showing a row of tabs reading All, Unread, Read, Important, and Archived, with the All tab selected and carrying an unread count

One feed offering five tabs, each a different filter over the same messages.

Tabs and feeds are web only. React, Vue, Angular, and the Web Components take them. The iOS, Android, Flutter, and React Native inboxes render a single list, so build the equivalent switch in your own UI with .

What each field does

A feed is a container. It creates nothing on its own, and only its tabs load messages. datasetId has to be unique across all feeds, not just within one. Tabs are flattened into one set of datasets when the inbox registers them. Two tabs sharing an ID become a single dataset that both render, so you get identical messages under two names and no error explaining it. Slugify the title and prefix it with the feed’s, as in jobs-unread.

Filter a tab

Set fields are AND’d together. Several tags match as OR, so a message carrying any one of them is included. Tags come from the send side. covers putting them on a message, and a tag has to be on the message before it arrives, because a filter cannot add one later. from is how you keep an existing user’s backlog out of a newly added tab. Pin it to the moment the tab shipped and the tab starts empty rather than full of history.

Several feeds

Give the inbox more than one feed and the header gains a picker. Each feed brings its own tabs.
The Courier Inbox feed picker open, listing All, Jobs, My Posts, and Mentions as selectable feeds

Four feeds in the header picker, each with its own set of tabs.

The chrome adapts to what you pass. One feed hides the feed picker. A feed holding one tab hides the tab bar and moves that tab’s unread count next to the feed name. So a single unfiltered feed and tab renders as a plain list, which is what an inbox with no feeds at all shows.

Select a feed or tab in code

The inbox element exposes selectFeed(feedId) and selectTab(datasetId), and reports changes back through onFeedChange and onTabChange. Both take the ids you defined above.
On React, Vue, and Angular these are methods on the underlying element rather than props, so reach them through a ref. To change what the tabs contain instead of which one is showing, pass a new feeds array and the inbox re-registers.

Unread counts

Each tab carries its own unread count, and totalUnreadCount on the datastore counts every message rather than the selected tab’s. A tab filtered to status: 'unread' empties as the reader works through it, because a message that leaves the filter leaves the tab.