Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

PreferencesMatrix

On and off choices in groups, against channels such as email and push.

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

Demo

MoneyEmailTextPush
Payouts
DisputesAlways emailed

When to use it

Use it for

  • Notification preferences across channels, on a SettingsPage with width="narrow"
  • Any set of yes-or-no choices that share the same columns

Not for

  • One channel: use a list of Switches or Checkboxes
  • Choices that wait for a Save across the whole page: put the matrix in a SettingsSection form

Examples

Locked security alerts

Preferences in two tabs, with security alerts locked on by email.

SecurityEmailText
New sign-inAlways emailed, so you hear about it

Notification settings

A settings section for the shop's notifications: the matrix holds a draft, and Save or Cancel settle it.

Notifications

Choose how the shop tells you about money and stock.

MoneyEmailTextPush
Payouts
DisputesAlways emailed
StockEmailTextPush
Low green coffeeWhen a coffee drops under 20 kg

No changes yet

Team notifications

Team notifications across email and push, controlled, with a summary of what's on.

MoneyEmailPush
Payouts
Refunds

1 on

Variants and states

Notification preferences

Groups of rows against the channels; a locked cell holds its value greyed.

MoneyEmailTextPush
Payouts
DisputesAlways emailed
StockEmailTextPush
Low green coffee

Props

PreferencesMatrix

PropTypeDefaultDescription
label

required

stringNames the matrix, and its tab row when it has more than one tab, such as "Notifications".
channels

required

readonly PreferenceChannel[]The ways to be told, its columns, in order.
tabs

required

readonly PreferenceTab[]Its tabs, each with groups of rows. With one, no tab row shows.
valuePreferenceValueWhich channels are on for each row. Pair with onValueChange to control it.
defaultValuePreferenceValueThe value it starts with when uncontrolled. Defaults to every channel off.
onValueChange((value: PreferenceValue) => void)Called with the whole value whenever a box is ticked or cleared, locked channels included as they're held.
tabstringThe tab shown. Pair with onTabChange to control it.
defaultTabstringThe tab shown first when uncontrolled. Defaults to the first.
onTabChange((tab: string) => void)Called when another tab is chosen.

It also takes Omit<ComponentPropsWithRef<"div">, "defaultValue" | "onChange">.

PreferenceChannel

One way to be told, a column of the matrix, such as Email.

FieldTypeDefaultDescription
id

required

stringIdentifies the channel in the value.
label

required

stringIts column's header, such as "Email".

PreferenceTab

A tab of the matrix, such as Account, holding its groups.

FieldTypeDefaultDescription
id

required

stringIdentifies the tab.
label

required

stringIts label in the tab row.
groups

required

readonly PreferenceGroup[]Its groups.

PreferenceGroup

Rows under one heading, the channels' headers repeated beside it.

FieldTypeDefaultDescription
id

required

stringIdentifies the group.
title

required

stringIts heading, such as "Money".
rows

required

readonly PreferenceRow[]Its rows.

PreferenceRow

One thing to be told about, a row of the matrix.

FieldTypeDefaultDescription
id

required

stringIdentifies the row in the value.
label

required

stringWhat it's about, such as "Payouts", the row's header.
descriptionstringA line under the label.
lockedReadonly<Partial<Record<string, boolean>>>Channels this row can't change, each held on (true) or off (false) and drawn greyed. The value reports them as held.

Accessibility

A group named by label. Each group is a table named by its title, whose heading row repeats the channels as column headers and whose rows' labels are row headers. Each cell is a checkbox named for its channel and row, such as "Email for Payouts"; a locked cell is a disabled checkbox holding its value. With more than one tab, underline Tabs switch the tables.

KeysWhat they do
TabMoves from the tab row into the tables and through their checkboxes row by row, skipping locked ones
SpaceTicks or clears the checkbox with focus
Left or Right arrowMoves to the tab before or after and shows its tables, when there's more than one tab
Home or EndShows the first or last tab

Motion

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

With reduced motion: The tab row's underline moves to the chosen tab at once.

Layout

It fills its container. Each group is a table as wide as the matrix, each channel's column 64px and the row labels taking the rest, their words wrapping. Rows are padded 12px above and below with a 1px line between them, groups sit 32px apart and the tab row 24px above them. Each checkbox is 18px with a 24px target.

See it in the roastery demo's settings.