|Kit

Button Multi Select

Pick several values from a row of joined Buttons — each one toggles independently. ButtonSelect's multiple-choice twin, on Ark UI's ToggleGroup machine.

ButtonMultiSelect works like ButtonSelect, but each item toggles independently and the value is an array. It covers text-formatting toggles, weekday pickers and filter rows. It has the same items, variants, sizes, colors and Field integration as ButtonSelect; only the value changes shape.

import { ButtonMultiSelect } from "@42-central/ui-react/button-multi-select";

<ButtonMultiSelect data={["Mon", "Tue", "Wed"]} defaultValue={["Mon"]} />;

Playground

ButtonMultiSelect

Loading preview

Props

Code

<ButtonMultiSelect
  orientation="horizontal"
  size="sm"
  color="brand"
/>

Items

data takes the same items as ButtonSelect: bare strings, or { value, label?, startSlot?, endSlot?, disabled?, color?, "aria-label"?, payload? } objects. Each item can have its own color, and any item can be disabled.

Variants

variant styles the unselected items (default light) and selectedVariant the selected ones (default filled). Both accept any Button variant.

Controlled

value is an array of your data's literal values, and onChange passes the next array.

value: ["Mon","Wed","Fri"]

Code

const [days, setDays] = useState(['Mon', 'Wed', 'Fri'])

<ButtonMultiSelect data={DAYS} value={days} onChange={setDays} color="brand" size="sm" />

Custom rendering

renderItem works as it does on ButtonSelect: it receives the typed item and its live { selected, disabled } state.

Orientation

Label, description & error

The campus is open on the selected days.
Pick at least one day

Composition

Build the group from ButtonMultiSelect.Root and ButtonMultiSelect.Item when data isn't enough. Root sets variant, selectedVariant, size and color for every item. Each item renders a Button and takes its props. With asChild, it renders your own control instead: here an ActionIcon per formatting toggle. The child receives the selection-driven variant and the group size (its own size wins). Icon-only items need an aria-label.

Code

<ButtonMultiSelect.Root aria-label="Formatting" defaultValue={['bold']} variant="subtle" selectedVariant="light" size="sm">
  <ButtonMultiSelect.Item value="bold" asChild>
    <ActionIcon aria-label="Bold"><Bold /></ActionIcon>
  </ButtonMultiSelect.Item>
  <ButtonMultiSelect.Item value="italic" asChild>
    <ActionIcon aria-label="Italic"><Italic /></ActionIcon>
  </ButtonMultiSelect.Item>
  <ButtonMultiSelect.Item value="underline" asChild>
    <ActionIcon aria-label="Underline"><Underline /></ActionIcon>
  </ButtonMultiSelect.Item>
  <ButtonMultiSelect.Item value="strike" asChild>
    <ActionIcon aria-label="Strikethrough"><Strikethrough /></ActionIcon>
  </ButtonMultiSelect.Item>
</ButtonMultiSelect.Root>

Forms

name renders one hidden input per selected value, all with the same name, so FormData.getAll(name) returns the selection.

Code

<form action={save}>
  <ButtonMultiSelect name="days" label="Days" data={DAYS} defaultValue={['Mon', 'Tue']} />
</form>

API

Prop

Type

Accessibility

  • Built on Ark UI's ToggleGroup machine in multiple mode: the group is a role="group" of toggle buttons with aria-pressed.
  • Roving focus: Tab enters and leaves the group. Arrow keys and Home / End move focus, and Space / Enter toggles the focused item.
  • The label, description and error are wired to the group through the built-in Field. Icon-only items need an aria-label.
  • In a right-to-left locale (from IntlProvider), the joined corners mirror and ← / → follow the visual order.

Changelog

v0.16.0
  • New ButtonSelect and ButtonMultiSelect: single- and multiple-choice rows of joined Buttons

    #252

On this page