Skip to main content
Kaleidoscope

SegmentedControl

Use SegmentedControls to offer 2—4 related, but mutually exclusive options to choose from.

Default

SegmentedControl displays a short list of options for users to choose from. It's usually best to have an option selected by default, but the component also supports an null initial selected value for when an initial selection can't be determined.

Editable example
() => {
  const [selected, setSelected] = React.useState("s");

  return (
    <SegmentedControl
      label="Block width"
      onChange={setSelected}
      value={selected}
    >
      <SegmentedControlOption label="Small" value="s" />
      <SegmentedControlOption label="Medium" value="m" />
      <SegmentedControlOption label="Large" value="l" />
    </SegmentedControl>
  );
}

Best practices

  1. Don't use a SegmentedControl as a binary switch (e.g. "on" and "off").
  2. Don't use for more than 4 options, or less than 2 options.
  3. Make sure your labels are short enough to fit comfortably in the available width.

Sizes

By default, SegmentedControls are medium sized. For using in context with other large sized controls, or in less dense UIs such as onboarding flows, use the large SegmentedControlSize.

Editable example
() => {
  const [control1, setControl1] = React.useState(1);
  const [control2, setControl2] = React.useState(1);
  const [control3, setControl3] = React.useState(1);
  const [control4, setControl4] = React.useState(1);

  return (
    <React.Fragment>
      <SegmentedControl
        label="Extra small"
        size="xs"
        onChange={setControl1}
        value={control1}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
      </SegmentedControl>
      <SegmentedControl
        label="Small"
        size="s"
        onChange={setControl2}
        value={control2}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
      </SegmentedControl>
      <SegmentedControl
        label="Medium"
        onChange={setControl3}
        value={control3}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
      </SegmentedControl>
      <SegmentedControl
        label="Large"
        size="l"
        onChange={setControl4}
        value={control4}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
      </SegmentedControl>
    </React.Fragment>
  )
}

Number of options

SegmentedControls are best suited to 2—4 options. Anything beyond that you should consider using another component such as a or . If you only have a single option use a .

Keep in mind the available space for each option's label. Consider abbreviating labels or using icons when space is limited.

Editable example
() => {
  const [control1, setControl1] = React.useState(1);
  const [control2, setControl2] = React.useState(1);
  const [control3, setControl3] = React.useState(1);

  return (
    <React.Fragment>
      <SegmentedControl
        label="Two options"
        onChange={setControl1}
        value={control1}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
      </SegmentedControl>
      <SegmentedControl
        label="Three options"
        onChange={setControl2}
        value={control2}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
        <SegmentedControlOption label="Option 3" value={3} />
      </SegmentedControl>
      <SegmentedControl
        label="Four options"
        onChange={setControl3}
        value={control3}
      >
        <SegmentedControlOption label="Option 1" value={1} />
        <SegmentedControlOption label="Option 2" value={2} />
        <SegmentedControlOption label="Option 3" value={3} />
        <SegmentedControlOption label="Option 4" value={4} />
      </SegmentedControl>
    </React.Fragment>
  );
}

Icon options

Use icons for options that can be clearly identified with a simple icon. Include a visible label within the option, or pair icon options with a tooltip using the baked in tooltip prop for extra clarity, particularly for less common or more ambiguous icons.

Editable example
() => {
  const [selectedView, setSelectedView] = React.useState("library");
  const [selectedAlign, setSelectedAlign] = React.useState("left");
  const [selectedFrame, setSelectedFrame] = React.useState("none");

  return (
    <React.Fragment>
      <SegmentedControl
        labelHidden
        label="Library"
        onChange={setSelectedView}
        value={selectedView}
      >
        <SegmentedControlOption icon={<Library />} label="Library" value="library" />
        <SegmentedControlOption icon={<Explore />} label="Explore" value="explore" />
      </SegmentedControl>
      <SegmentedControl
        label="Alignment"
        onChange={setSelectedAlign}
        value={selectedAlign}
      >
        <SegmentedControlOption labelHidden icon={<AlignLeft />} label="Left" value="left" />
        <SegmentedControlOption labelHidden icon={<AlignCenter />} label="Center" value="center" />
      </SegmentedControl>
      <SegmentedControl
        label="Image frame"
        onChange={setSelectedFrame}
        value={selectedFrame}
      >
        <SegmentedControlOption labelHidden tooltip={{ content: "No frame" }} icon={<FrameNone />} label="None" value="none" />
        <SegmentedControlOption labelHidden tooltip={{ content: "Circular frame" }} icon={<FrameCircle />} label="Circle" value="circle" />
      </SegmentedControl>
    </React.Fragment>
  );
}

End element

To render content at the end of a SegmentedControlOption, use the endElement prop.

Editable example
() => {
  const [value, setValue] = React.useState(1);

  return (
    <React.Fragment>
      <SegmentedControl
        label="End element"
        onChange={setValue}
        value={value}
      >
        <SegmentedControlOption
          label="First option"
          value={1}
          endElement={
            <Label
              size="s"
              style={{
                borderRadius: 32,
                background: tokens.color.surfaceSuccess,
                paddingInline: tokens.spacing.xs,
                paddingBlock: tokens.spacing.xxxs,
                color: tokens.color.textSuccess,
              }}
            >
              New
            </Label>
          }
        />
        <SegmentedControlOption label="Second option" value={2} />
      </SegmentedControl>
    </React.Fragment>
  );
}

Asymmetric

By default, SegmentedControl options are equal width. To allow options to be of variable widths, use the asymmetric prop.

Editable example
() => {
  const [value, setValue] = React.useState(1);

  return (
    <React.Fragment>
      <SegmentedControl
        asymmetric
        label="Asymmetric"
        onChange={setValue}
        value={value}
      >
        <SegmentedControlOption label="First option" value={1} />
        <SegmentedControlOption label="Second option with a long label" value={2} />
      </SegmentedControl>
    </React.Fragment>
  );
}

Errors

Use the error prop to set any validation errors.

Editable example
() => {
  const [value, setValue] = React.useState(null);

  return (
    <SegmentedControl
      label="Select an option"
      onChange={setValue}
      value={value}
      error={value === null ? "Please select an option" : undefined}
    >
      <SegmentedControlOption label="First option" value={1} />
      <SegmentedControlOption label="Second option" value={2} />
    </SegmentedControl>
  );
}

Disabled options

Individual options can be disabled using the disabled prop on SegmentedControlOption.

Editable example
() => {
  const [value, setValue] = React.useState(1);

  return (
    <SegmentedControl
      label="Disabled example"
      onChange={setValue}
      value={value}
    >
      <SegmentedControlOption label="Available" value={1} />
      <SegmentedControlOption label="Disabled" value={2} disabled />
      <SegmentedControlOption label="Also available" value={3} />
    </SegmentedControl>
  );
}

Start element

Use the startElement prop on SegmentedControlOption to render content before the label, similar to endElement.

Editable example
() => {
  const [value, setValue] = React.useState("active");

  return (
    <SegmentedControl
      label="Status"
      onChange={setValue}
      value={value}
    >
      <SegmentedControlOption label="Active" value="active" startElement={<Tick />} />
      <SegmentedControlOption label="Archived" value="archived" />
    </SegmentedControl>
  );
}

Accessibility

  • Always include a label that describes the group of choices, e.g. "Block width". If the grouping of options is self-evident or implied by context, use the labelHidden prop so the label will not appear visually but still be read by assistive technology.
  • Always include labels for options, even icon options. The label is used as the aria-label attribute for icon options. You can also use a tooltip for icon options.