Components

ButtonGroup

ButtonGroup allows authors to stylistically group a set of related Buttons or construct a group of selectable Buttons that behave like Radios or Checkboxes.

Examples #

Import Syntax #

import ButtonGroup from 'mineral-ui/ButtonGroup';

Basic #

ButtonGroups stylistically group a set of buttons together.

<ButtonGroup aria-label="Edit text">
  <Button>Cut</Button>
  <Button>Copy</Button>
  <Button>Paste</Button>
</ButtonGroup>

Mode #

Use the mode prop to render toggleable Buttons. A value of radio will cause Buttons to behave like radio buttons and a value of checkbox will cause Buttons to behave like checkboxes.

<DemoLayout>
  <ButtonGroup
    mode="radio"
    aria-label="Align text"
    defaultChecked={0}>
    <Button>Left</Button>
    <Button>Center</Button>
    <Button>Right</Button>
  </ButtonGroup>
  <ButtonGroup
    mode="checkbox"
    aria-label="Text Decoration"
    defaultChecked={[0, 1]}>
    <Button>Bold</Button>
    <Button>Italic</Button>
    <Button>Underline</Button>
  </ButtonGroup>
</DemoLayout>

Uncontrolled #

Create an uncontrolled ButtonGroup by using the defaultChecked prop rather than the checked prop. Note that the defaultChecked prop may be set on the root (where the value may be a number representing the index of the Button to check or an array of those indices, based on the zero-indexed collection of nested Buttons) or on individual children (where the value is a boolean).

<ButtonGroup aria-label="Align text" mode="radio">
  <Button defaultChecked>Left</Button>
  <Button>Center</Button>
  <Button>Right</Button>
</ButtonGroup>

Controlled #

Provide the checked prop and an onChange handler to create a controlled component.

() => {
  class MyForm extends Component {
    constructor(props) {
      super(props);

      this.state = {
        checked: 0
      };

      this.handleChange = this.handleChange.bind(this);
      this.resetDefaultSelected = this.resetDefaultSelected.bind(this);
    }

    handleChange(event) {
      this.setState({
        checked: parseInt(event.target.getAttribute('data-index'))
      });
    }

    resetDefaultSelected() {
      this.setState({
        checked: 0
      });
    }

    render() {
      return (
        <DemoLayout>
          <ButtonGroup
            aria-label="Align text"
            checked={this.state.checked}
            onChange={this.handleChange}
            mode="radio">
            <Button>Left</Button>
            <Button>Center</Button>
            <Button>Right</Button>
          </ButtonGroup>
          <Button minimal size="small" onClick={this.resetDefaultSelected}>Reset to Default Alignment</Button>
        </DemoLayout>
      );
    }
  }

  return <MyForm />;
}

Sizes #

To provide hierarchy to actions on your page, change ButtonGroup impact with the size attribute.

For a ButtonGroup whose width is defined by its container, use fullWidth.

() => {
  const sizes = ['small', 'medium', 'large', 'jumbo'];

  return (
    <DemoLayout>
      {
        sizes.map((size) => (
          <ButtonGroup size={size} aria-label="Edit text" key={size}>
            <Button>Cut</Button>
            <Button>Copy</Button>
            <Button>Paste</Button>
          </ButtonGroup>
        ))
      }
      <ButtonGroup fullWidth aria-label="Edit text">
        <Button>Cut</Button>
        <Button>Copy</Button>
        <Button>Paste</Button>
      </ButtonGroup>
    </DemoLayout>
  );
}

Variants #

Use the variant prop to help communicate purpose. Note that the variant prop may be set on the root or on individual children.

<DemoLayout>
  <ButtonGroup variant="success" aria-label="Shopping options">
    <Button>Donate $5</Button>
    <Button>Donate $10</Button>
  </ButtonGroup>
  <ButtonGroup variant="warning" aria-label="Shopping options">
    <Button>Revoke Author Permissions</Button>
    <Button>Revoke Group Permissions</Button>
  </ButtonGroup>
  <ButtonGroup variant="danger" aria-label="Shopping options">
    <Button>Send Storm Watch</Button>
    <Button>Send Storm Warning</Button>
  </ButtonGroup>
</DemoLayout>

Disabled #

Use disabled to indicate that Buttons are not available for interaction. Note that the disabled prop may be set on the root or on individual children.

<DemoLayout>
  <ButtonGroup disabled aria-label="Edit text">
    <Button>Cut</Button>
    <Button>Copy</Button>
    <Button>Paste</Button>
  </ButtonGroup>

  <ButtonGroup aria-label="Edit text">
    <Button disabled>Cut</Button>
    <Button>Copy</Button>
    <Button>Paste</Button>
  </ButtonGroup>

  <ButtonGroup
    disabled
    aria-label="Align text"
    defaultChecked={0}
    mode="radio">
    <Button>Left</Button>
    <Button>Center</Button>
    <Button>Right</Button>
  </ButtonGroup>

  <ButtonGroup aria-label="Align text" defaultChecked={0} mode="radio">
    <Button>Left</Button>
    <Button>Center</Button>
    <Button disabled>Right</Button>
  </ButtonGroup>
</DemoLayout>

Icons #

Buttons within ButtonGroup can contain Icons, just as they do in Button

<DemoLayout>
  <ButtonGroup aria-label="Align text" mode="radio">
    <Button defaultChecked iconStart={<IconFormatAlignLeft />}>Left</Button>
    <Button iconStart={<IconFormatAlignCenter />}>Center</Button>
    <Button iconStart={<IconFormatAlignRight />}>Right</Button>
  </ButtonGroup>

  <ButtonGroup aria-label="Format text" mode="checkbox">
    <Button iconEnd={<IconFormatBold />} aria-label="Bold" />
    <Button iconEnd={<IconFormatItalic />} aria-label="Italic" />
    <Button iconEnd={<IconFormatUnderlined />} aria-label="Underlined" />
  </ButtonGroup>

  <ButtonGroup aria-label="Sentiments" mode="radio">
    <Button
      variant="success"
      iconEnd={<IconSentimentSatisfied />}
      aria-label="Satisfied" />
    <Button
      variant="warning"
      iconEnd={<IconSentimentNeutral />}
      aria-label="Neutral" />
    <Button
      variant="danger"
      iconEnd={<IconSentimentDissatisfied />}
      aria-label="Unsatisfied" />
  </ButtonGroup>
</DemoLayout>

Composition #

Other Mineral components that render a Mineral Button, such as Tooltip, Popover, or Dropdown, may be composed in a ButtonGroup, though they are incompatible with the mode prop.

<FixedWidthLayout>
  <ButtonGroup aria-label="Optional compositions">
    <Button>Button</Button>
    <Tooltip content="Lorem ipsum dolor sit amet">
      <Button>Tooltip</Button>
    </Tooltip>
    <Popover content={<DemoContent />}>
      <Button>Popover</Button>
    </Popover>
    <Dropdown data={data}>
      <Button iconEnd={<IconArrowDropDown />}>Dropdown</Button>
    </Dropdown>
  </ButtonGroup>
</FixedWidthLayout>

Bidirectionality #

ButtonGroups support right-to-left (RTL) languages. Buttons within ButtonGroup behave like Button (Icons are reversed when the direction theme variable is set to rtl. A subset of Icons that convey directionality will be reversed).

<div dir="rtl">
  <ThemeProvider theme={{ direction: 'rtl' }}>
    <ButtonGroup aria-label="Format text" mode="checkbox">
      <Button iconEnd={<IconFormatBold />}>بالخط العريض</Button>
      <Button iconEnd={<IconFormatItalic />}>مائل</Button>
      <Button iconEnd={<IconFormatUnderlined />}>أكد</Button>
    </ButtonGroup>
  </ThemeProvider>
</div>

API & Theme #

ButtonGroup Props #

The ButtonGroup component takes the following React props.

NameTypeDefaultDescription
aria-labelstringrequired

Accessible label

checkednumber | Array<number>

Index or array of indices of the selected Button(s). Primarily for use with controlled components with a mode prop defined. If this prop is specified, an onClick handler must also be specified. See also: defaultChecked

childrenReact$Noderequired

Mineral Button components

defaultCheckednumber | Array<number>

Index or array of indices of the selected Button(s); primarily for use with uncontrolled components with a mode prop defined.

disabledboolean

Disable all Button children

fullWidthboolean

Stretch ButtonGroup to fill its container

mode'checkbox' | 'radio'

Behavioral mode of Button children: either Radio or Checkbox

onChange

Called when a toggleable Button is selected

onClick

Called with the click event

size'small' | 'medium' | 'large' | 'jumbo'

Available sizes

variant'danger' | 'success' | 'warning'

Available variants

Undocumented properties, including as and css, will be applied to the root element.

ButtonGroup Theme Variables #

These variables can be used as hooks to override this component's style at either a local or global level. The theme referenced below is whatever theme is available from props to the instance of this component.

VariableValue
ButtonGroupButton_backgroundColor_checkedDisabledtheme.color_gray_40
ButtonGroupButton_border_disabledsolid 1px borderColor
ButtonGroupButton_borderColor_activetheme.borderColor_theme_active
ButtonGroupButton_borderColor_hovertheme.borderColor_theme_hover
ButtonGroupButton_borderStartColortheme.borderColor
ButtonGroupButton_borderStartColor_checkedcurrentcolor
ButtonGroupButton_color_checkedDisabledtheme.color_gray_60

Usage #

When/How to Use #

ButtonGroup allows users to stylistically group related buttons or to select either a single or multiple options from a group of related buttons.

Although ButtonGroups can mimic radio-button and checkbox behaviors, the elements do not behave as their HTML counterparts during traditional form submission and thus should not be used as replacements for radios and checkboxes if that functionality is needed. In such scenarios, Radio or Checkbox should be used instead.

Best Practices #

Where space allows, add text to accompany icons in order to clarify purpose.

Don't use ButtonGroup for unrelated buttons.

Don't use long words or more than three words to describe a ButtonGroup Button; instead, be as descriptive and concise as possible.

Don't use varying sizes for adjacent ButtonGroups.

Don't use ButtonGroups for navigation; use tabs instead.