SegmentedControl may be used to group multiple selections. The controls display the current state and related state.

Create layout to convey clear sense of information hierarchy. When a control is engaged, information below the control should also be updated.

also known as Toggle Group

Responsive:

Adaptive:

Props

Component props
Name
Type
Default
items
Required
$ReadOnlyArray<React.Node>
-

Items for selection. Though typically strings, React.Node is accepted to allow for Icons or other custom UI.

onChange
Required
({
  event: SyntheticMouseEvent<HTMLButtonElement>,
  activeIndex: number,
}) => void
-

Callback triggered when the user selects an item.

selectedItemIndex
Required
number
-

Index of element in items that is currently selected.

responsive
boolean
-

By default, items have equal widths. If this prop is true, the width of an item is based on its content. See the responsive example for more details.

size
"sm" | "md" | "lg"
"md"

Size of the Segmented Control.

Usage guidelines

When to use
  • To switch between views within a small area of content, such as a Popover.
When not to use
  • To switch between views that represent the main content of a surface. Use Tabs instead.
  • To act as a radio control within a form. Use RadioGroup instead.

Accessibility

Variants

Default

SegmentedControl is a naive component, meaning you need to wire any additional behavior when the user clicks on an item. If you'd like the tabs to control hiding or showing content, that state should live in a parent component.

import { useState } from 'react';
import { Box, Flex, Icon, SegmentedControl, Text } from 'gestalt';

export default function SegmentedControlExample() {
  const [itemIndex, setItemIndex] = useState(0);

  const items = [
    'News',
    'You',
    'Messages',
    <Icon key="icon" accessibilityLabel="Pin" color="default" icon="pin" />,
  ];

  const content = [
    'News content',
    'You content',
    'Messages content',
    'Pins content',
  ];

  return (
    <Box height="100%" padding={8}>
      <Flex direction="column" gap={{ column: 2, row: 0 }}>
        <SegmentedControl
          items={items}
          onChange={({ activeIndex }) => setItemIndex(activeIndex)}
          selectedItemIndex={itemIndex}
        />

        <Box borderStyle="shadow" padding={6} rounding={2}>
          <Text>{content[itemIndex]}</Text>
        </Box>
      </Flex>
    </Box>
  );
}

Responsive

SegmentedControl can have responsive widths where the width of an item is based on its content.

import { useState } from 'react';
import { Box, Flex, Heading, SegmentedControl } from 'gestalt';

export default function SegmentedControlExample() {
  const [item1Index, setItem1Index] = useState(0);
  const [item2Index, setItem2Index] = useState(0);
  const items = ['Short', 'Really really really long title'];

  return (
    <Box padding={8}>
      <Flex direction="column" gap={{ column: 6, row: 0 }}>
        <Flex direction="column" gap={{ column: 2, row: 0 }}>
          <Heading size="400">Equal widths</Heading>
          <SegmentedControl
            items={items}
            onChange={({ activeIndex }) => {
              setItem1Index(activeIndex);
            }}
            selectedItemIndex={item1Index}
          />
        </Flex>

        <Flex direction="column" gap={{ column: 2, row: 0 }}>
          <Heading size="400">Responsive widths</Heading>
          <SegmentedControl
            items={items}
            onChange={({ activeIndex }) => {
              setItem2Index(activeIndex);
            }}
            responsive
            selectedItemIndex={item2Index}
          />
        </Flex>
      </Flex>
    </Box>
  );
}

Size

SegmentedControl is available in 3 fixed sizes:
1. lg (48px)
Large should be used when SegmentedControl needs to span larger areas. The font is 16px.
2. md (40px)
Medium is the default size, and should be used on most pinner surfaces. The font is 16px.
3. sm (32px)
Small should be used in places where the UI is very dense. The font is 14px.

import { useState } from 'react';
import {
  Box,
  Flex,
  Heading,
  Icon,
  SegmentedControl,
  Switch,
  Text,
} from 'gestalt';

export default function SegmentedControlExample() {
  const [showIcons, setShowIcons] = useState(false);
  const [item1Index, setItem1Index] = useState(0);
  const [item2Index, setItem2Index] = useState(0);
  const [item3Index, setItem3Index] = useState(0);
  const textItems = ['All', 'Published', 'Drafts'];

  const iconItems = ['music-on', 'video-camera'].map((p) => (
    <Icon key="icon" accessibilityLabel={p} color="default" icon={p} />
  ));
  const items = showIcons ? iconItems : textItems;

  return (
    <Box padding={8} width="60%">
      <Flex alignItems="center" gap={2} height={48}>
        <Text> Show Icons</Text>
        <Switch
          id="showIcons"
          name="showIcons"
          onChange={({ value }) => setShowIcons(value)}
          switched={showIcons}
        />
      </Flex>
      <Flex direction="column" gap={{ column: 6, row: 0 }}>
        <Flex direction="column" gap={{ column: 2, row: 0 }}>
          <Heading size="300">sm</Heading>
          <SegmentedControl
            items={items}
            onChange={({ activeIndex }) => {
              setItem1Index(activeIndex);
            }}
            selectedItemIndex={item1Index}
            size="sm"
          />
        </Flex>

        <Flex direction="column" gap={{ column: 2, row: 0 }}>
          <Heading size="300">md</Heading>
          <SegmentedControl
            items={items}
            onChange={({ activeIndex }) => {
              setItem2Index(activeIndex);
            }}
            responsive
            selectedItemIndex={item2Index}
            size="md"
          />
        </Flex>
        <Flex direction="column" gap={{ column: 2, row: 0 }}>
          <Heading size="300">lg</Heading>
          <SegmentedControl
            items={items}
            onChange={({ activeIndex }) => {
              setItem3Index(activeIndex);
            }}
            responsive
            selectedItemIndex={item3Index}
            size="lg"
          />
        </Flex>
      </Flex>
    </Box>
  );
}

Component quality checklist

Component quality checklist
Quality item
Status
Status description
Figma Library
Partially ready
Component is live in Figma, however may not be available for all platforms.
Responsive Web
Ready
Component responds to changing viewport sizes in web and mobile web.