Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

Tabs

Tabs that switch the panel under them, underlined, as pills or boxed on a track, with a sliding marker and the tabs that don't fit in a menu.

import { Tabs } from "@butteryui/react";

Demo

Overview for Ines Vale.

tabs3

When to use it

Use it for

  • Sections of one record or page, such as a customer's overview, orders and notes
  • A page header's views, under its title
  • A quieter row, such as tabs inside a card, with variant="pills"; a few views of one thing, such as a chart, with variant="boxed"

Not for

  • Tabs that go to other pages: use TabNav
  • Two to five options that change one setting: use SegmentedControl
  • Counts per view, such as orders by state: use StatTabs

Examples

Coffee views

A coffee's views in boxed tabs, its chosen tab raised on a track, and its brew guides in pills under them.

Peach, jasmine and bergamot, with a clean finish.

Customer page

A customer's page: the tabs sit in the page header, and each panel holds that part of the record.

Ines Vale

A customer since March, with 14 orders.

Order 1042 · 2 bags of house blendRoasting
Order 1031 · 1 bag of decafShipped
Order 1019 · A tasting setShipped

Customer sections

A customer's page split into sections, one panel at a time.

Ines has ordered 14 times since March.

Narrow tabs

More tabs than room: the last ones fold into "…" and stay one press away.

General settings

Read the note

The chosen tab kept in state, so a button outside the tabs can open one.

Ines left a note this morning.

Ines has ordered 14 times since March.

Variants and states

Underlined tabs

The underline slides to the chosen tab on spring.snappy; arrow keys move along the row.

Overview for Ines Vale.

Pills and boxed

pills slides a bg-control pill behind the chosen tab, with no line under the row; boxed raises the chosen tab on a bg-control track. Both slide on spring.snappy, as the underline does.

Orders for Ines Vale.

Orders for Ines Vale.

Not enough room

In a narrow column, the last tabs fold into the … menu, whichever the variant.

Overview

Overview

Props

Tabs

PropTypeDefaultDescription
valuestringThe chosen tab's value. Pair with onValueChange to control it.
defaultValuestringThe tab chosen at first when uncontrolled.
onValueChange((value: string) => void)Called with the value of the tab chosen.
variant"underline" | "pills" | "boxed""underline"How the chosen tab is marked: "underline" (the default), a 2px underline on a line across the row, for a page's sections; "pills", a bg-control pill behind it, for a quieter row; or "boxed", raised on a bg-control track, for a few views of one thing. The marker slides on spring.snappy in each.

It also takes Omit<ComponentPropsWithRef<typeof RadixTabs.Root>, "value" | "defaultValue" | "onValueChange" | "orientation" | "activationMode" | "asChild">.

Tabs.List

PropTypeDefaultDescription
label

required

stringNames the tabs for screen readers, such as "Order sections".
moreLabelstring"More tabs"Names the button that lists the tabs that don't fit. Defaults to "More tabs".

It also takes Omit<ComponentPropsWithRef<typeof RadixTabs.List>, "asChild" | "aria-label">.

Tabs.Panel

PropTypeDefaultDescription
value

required

stringThe value of the tab that shows this panel.

It also takes Omit<ComponentPropsWithRef<typeof RadixTabs.Content>, "asChild">.

Tabs.Tab

PropTypeDefaultDescription
value

required

stringThe value that names the tab and its panel.
children

required

stringThe tab's label. It's also its entry in the "…" menu once it doesn't fit.

It also takes Omit<ComponentPropsWithRef<typeof RadixTabs.Trigger>, "asChild" | "children">.

Accessibility

A tablist named by its label; arrow keys move between tabs and choose them, Home and End jump to the ends, and Tab moves into the chosen panel, which is named by its tab. Tabs folded into the menu stay reachable from the More tabs button.

KeysWhat they do
TabMoves to the chosen tab, then to the More tabs button when some tabs have folded, then into the chosen panel
Arrow Right or Arrow LeftMoves to the next or previous tab in the row and shows its panel, wrapping at the ends
Home or EndMoves to the first or last tab in the row and shows its panel
Enter, Space or Arrow DownOpens the More tabs menu from its button
Arrow Down or Arrow UpMoves through the folded tabs in the menu
Enter or SpaceChooses the folded tab focused in the menu and shows its panel
EscapeCloses the menu and puts focus back on its button

Motion

Its selection indicator slides to the chosen option on `spring.snappy`, inside one track.

With reduced motion: The underline, pill or raised tab appears on the chosen tab at once instead of sliding there.

Layout

It fills its container's width: a row of tabs, then the chosen panel 24px below. Underlined, the row sits over a 1px line and each tab is --bt-h-button (36px) tall, 16px from the next; as pills, the tabs are 36px pills 4px apart with no line; boxed, they sit 2px inside a 36px bg-control track (r-lg), each 32px tall (r-md). Each tab is as wide as its label and wholly its own hit area; labels never wrap or truncate: the tabs that don't fit fold into the More tabs menu at the row's end, last ones first, and the chosen tab stays in the row.

See it in the Halfmoon shop demo.