Pattern

Tabs

Sections of a record or a page, as buttons that switch in place or links that navigate, with count pills.

Copy it from /dashboard/accounts/:acctId/sites/:siteId/submitted-forms/:kind?review=:id

Button tabs with counts and an indicator

Switch a section in place. The row is a tablist: each tab has role tab and the current one aria-selected, with no aria-current since nothing navigates, and Left, Right, Home, and End move between tabs. Give it an `id` from `useId` and spread `tabPanelProps(id, tab)` on the element that shows the selected section, which the selected tab’s aria-controls names. A count shows in a pill, zero included, and the flag marks flagged answers.

Route
/dashboard/accounts/:acctId/sites/:siteId/submitted-forms/:kind?review=:id
Screenshot
docs/agents/ui-patterns/drawer-tabs-footer-1440.png
The overview section.
<Tabs
  id={tabsId}
  items={[
    {
      key: 'overview',
      label: 'Overview',
    },
    {
      key: 'answers',
      label: 'Answers',
      count: 117,
      indicator: 'flag',
    },
    {
      key: 'contracts',
      label: 'Contracts',
      count: 0,
    },
    {
      key: 'notes',
      label: 'Notes',
      count: 5,
    },
    {
      key: 'history',
      label: 'History',
      count: 23,
    },
  ]}
  selected={tab}
  onSelect={setTab2}
/>
<div
  {...tabPanelProps(tabsId, tab)}
>
  {/* the selected section */}
</div>

Link tabs

Navigate. The tab whose path matches the page exactly is current, whatever the search string, so a link can keep the list’s filters. Here they switch between the gallery’s own pages; the snippet shows the paths the Animals layout builds.

Route
/dashboard/accounts/:acctId/sites/:siteId/animal-list/:group
<Tabs
  items={[
    {
      key: 'active',
      label: 'Active',
      count: 37,
      to: `${siteBaseUrl}/active`,
    },
    {
      key: 'action-required',
      label: 'Action Required',
      count: 701,
      to: `${siteBaseUrl}/action-required`,
    },
    {
      key: 'completed',
      label: 'Completed',
      count: 330,
      to: `${siteBaseUrl}/completed`,
    },
  ]}
/>

An overflowing row

The row never wraps or becomes a dropdown. It scrolls sideways, keeps the current tab in view clear of the fade, and fades at a clipped edge. When this page opens, Sponsors is current; each other tab opens its own gallery page, where that tab is current.

Route
/dashboard/accounts/:acctId/sites/:siteId/animals/:group/:id/edit
<Tabs
  items={[
    {
      key: 'edit',
      label: 'Edit Animal',
      to: `${siteBaseUrl}/edit`,
    },
    {
      key: 'medical',
      label: 'Medical',
      to: `${siteBaseUrl}/medical`,
    },
    {
      key: 'notes',
      label: 'Notes',
      to: `${siteBaseUrl}/notes`,
    },
    {
      key: 'submissions',
      label: 'Applications',
      count: 4,
      to: `${siteBaseUrl}/submissions`,
    },
    {
      key: 'contracts',
      label: 'Contracts',
      count: 2,
      to: `${siteBaseUrl}/contracts`,
    },
    {
      key: 'history',
      label: 'History',
      to: `${siteBaseUrl}/history`,
    },
    {
      key: 'sponsors',
      label: 'Sponsors',
      count: 3,
      to: `${siteBaseUrl}/sponsors`,
    },
  ]}
/>