> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Segmented Control - Web

> Segmented Controls switch the presentation view of current or filtered content, such as displaying content in list view vs. a card view.

> [!NOTE]
>
> For development, import `SegmentedControl` from
> `@servicetitan/anvil2`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3?node-id=161-563).

![](https://mintcdn.com/servicetitan/H5FwKyiqhPVZ1UJQ/images/docs/web/components/shared/segmented-control-main.png?fit=max\&auto=format\&n=H5FwKyiqhPVZ1UJQ\&q=85\&s=ad95de22d0949d53272505735227c1c4)

## Anatomy

The Segmented Control has three elements that work together to switch the presentation view of current or filtered content.

![segmented control
anatomy](https://mintcdn.com/servicetitan/Z-EIF5iqj0kJVjT1/images/docs/web/components/segmented-control/design/segmented-control-anatomy.png?fit=max\&auto=format\&n=Z-EIF5iqj0kJVjT1\&q=85\&s=a1f137a51380b968f821aa03f615c7b0)

1. Selected segment
2. Icon
3. Label

## Options

The Segmented Control supports multiple sizes, fill options, and icon configurations for different use cases.

### Sizes

segmentedcontrol-size

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-size?file=src/App.tsx)

```tsx lines theme={null}
import { SegmentedControl, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex gap="6" direction="column">
      <SegmentedControl defaultSelected="level 1" size="small">
        <SegmentedControl.Segment value="level 1">
          Level 1
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2">
          Level 2
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 3">
          Level 3
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 4">
          Level 4
        </SegmentedControl.Segment>
      </SegmentedControl>
      <SegmentedControl defaultSelected="level 1" size="medium">
        <SegmentedControl.Segment value="level 1">
          Level 1
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2">
          Level 2
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 3">
          Level 3
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 4">
          Level 4
        </SegmentedControl.Segment>
      </SegmentedControl>
    </Flex>
  );
}

export default App;
```

### Fill

By default, Segmented Control will hug its content. But it can also fill available width.

segmentedcontrol-fill

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-fill?file=src/App.tsx)

```tsx lines theme={null}
import { SegmentedControl } from "@servicetitan/anvil2";

function App() {
  return (
    <SegmentedControl defaultSelected="level 1" fill>
      <SegmentedControl.Segment value="level 1">
        Level 1
      </SegmentedControl.Segment>
      <SegmentedControl.Segment value="level 2">
        Level 2
      </SegmentedControl.Segment>
      <SegmentedControl.Segment value="level 3">
        Level 3
      </SegmentedControl.Segment>
      <SegmentedControl.Segment value="level 4">
        Level 4
      </SegmentedControl.Segment>
    </SegmentedControl>
  );
}

export default App;
```

### Icons

segmentedcontrol-icon

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-icon?file=src/App.tsx)

```tsx lines theme={null}
import { SegmentedControl, Flex, Tooltip } from "@servicetitan/anvil2";
import List from "@servicetitan/anvil2/assets/icons/material/round/list.svg";
import GridView from "@servicetitan/anvil2/assets/icons/material/round/grid_view.svg";

function App() {
  return (
    <Flex gap="6" direction="column">
      <SegmentedControl defaultSelected="list">
        <SegmentedControl.Segment value="list" icon={List}>
          List
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="grid" icon={GridView}>
          Grid
        </SegmentedControl.Segment>
      </SegmentedControl>
      <SegmentedControl defaultSelected="list">
        <Tooltip>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="list"
              icon={List}
              aria-label="List view"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>List</Tooltip.Content>
        </Tooltip>
        <Tooltip>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="grid"
              icon={GridView}
              aria-label="Grid view"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>Grid</Tooltip.Content>
        </Tooltip>
      </SegmentedControl>
    </Flex>
  );
}

export default App;
```

Place icons before the segment's text label, or use them to replace the text label as an icon-only segment.

Use icon-only segments with Tooltip to provide an accessible label.

## Behavior

The Segmented Control responds to user interaction with distinct visual states and selection behaviors.

### Visual States

#### Default

Default segments do not have a focus-visible state because only the selected segment receives focus.

segmentedcontrol-data-interactive

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-data-interactive?file=src/App.tsx)

```tsx lines theme={null}
import { SegmentedControl, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex gap="6" direction="column">
      <SegmentedControl defaultSelected="level 1">
        <SegmentedControl.Segment value="level 1">
          Selected
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2">
          Default
        </SegmentedControl.Segment>
      </SegmentedControl>
      <SegmentedControl defaultSelected="level 1">
        <SegmentedControl.Segment value="level 1">
          Selected
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2" data-interactive="hover">
          Default Hover
        </SegmentedControl.Segment>
      </SegmentedControl>
      <SegmentedControl defaultSelected="level 1">
        <SegmentedControl.Segment value="level 1">
          Selected
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2" data-interactive="active">
          Default Active
        </SegmentedControl.Segment>
      </SegmentedControl>
    </Flex>
  );
}

export default App;
```

#### Selected

Selected segments do not have hover or active states because users cannot interact with them when selected.

segmentedcontrol-data-interactive-selected

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-data-interactive-selected?file=src/App.tsx)

```tsx lines theme={null}
import { SegmentedControl, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex gap="6" direction="column">
      <SegmentedControl defaultSelected="level 1">
        <SegmentedControl.Segment value="level 1">
          Selected Default{" "}
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2">
          Other Segment
        </SegmentedControl.Segment>
      </SegmentedControl>
      <SegmentedControl defaultSelected="level 1">
        <SegmentedControl.Segment
          value="level 1"
          data-interactive="focus-visible"
        >
          Selected Focus Visible
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2">
          Other Segment
        </SegmentedControl.Segment>
      </SegmentedControl>
    </Flex>
  );
}

export default App;
```

* Only one segment remains selected at all times
* At least one segment remains selected at all times

### Focused

Only the selected segment receives focus.

## Usage Guidelines

| Standard | Requirement |
| - | - |
| DoSwitch the presentation view | Use the Segmented Control when switching the presentation view of current or filtered content. |
| DoUse for 2-5 selections | Use Segmented Control for 2-5 selections. Currently it lacks native overflow handling, so test for mobile responsiveness when using this component. |
| DoToggle between presentation modes | Use Segmented Control to toggle between different presentation modes such as grid vs list. |
| DoFilter content | Use Segmented Control to filter data into segments, providing users with a smaller set of data to engage. Including a number helps indicate how many items are in each filtered segment. |
| DoSort content | Use Segmented Control to allow users to sort a list or display by different criteria (e.g., "Newest," "Oldest," "Most Popular," "Alphabetical"). The core content remains the same, but its order changes. |
| DoSwitch data granularity or time ranges | Use Segmented Control to toggle between different temporal views of the same data or different interpretations of the same data. Another example includes switching between a percentage (%) or dollar amount (\$). |
| DoToggle sub-categories | Use Segmented Control when a section has closely related, but distinct, sub-sections. |
| DoSelect an option in a form | Use Segmented Control for a small number of mutually exclusive choices within a form. It provides a visually appealing and efficient alternative to traditional radio buttons, especially when space is a concern. |
| Don'tUse for explicit-submission choices | Radios are form controls that users must explicitly submit; use Segmented Controls instead for selections that affect the UI immediately. |
| Don'tUse to show new content | Segmented Control changes the presentation format of displayed content or filters it; use Tabs instead to change the view and show new content. |

## Content

Use labels and icons to clearly communicate each segment option.

## Keyboard Interaction

Users can navigate the Segmented Control using standard keyboard controls.

| Key | Interaction |
| - | - |
| Arrow Right | While focused, selects the Segment on the right |
| Arrow Left | While focused, selects the Segment on the left |

### Accessibility

* Icon-only segments require an accessible name via `aria-label` or `aria-describedby`.

For more guidance on form field labels and context, see [input field context association best practices](https://anvil.servicetitan.com/docs/accessibility/labels-and-ctas.md#input-field-context-association).

## Code

**Implementation**

segmentedcontrol-playground

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-playground?file=src/App.tsx)

```tsx lines expandable theme={null}
import { SegmentedControl, Flex } from "@servicetitan/anvil2";
import MenuIcon from "@servicetitan/anvil2/assets/icons/material/round/menu.svg";
import { useState } from "react";

function App() {
  const [selected, setSelected] = useState("level 2");

  return (
    <Flex direction="column" gap="6">
      <SegmentedControl selected={selected} onChange={setSelected}>
        <SegmentedControl.Segment value="level 1" icon={MenuIcon}>
          Level 1
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2" icon={MenuIcon}>
          Level 2
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 3" icon={MenuIcon}>
          Level 3
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 4" icon={MenuIcon}>
          Level 4
        </SegmentedControl.Segment>
      </SegmentedControl>
    </Flex>
  );
}

export default App;
```

## Common Examples

```tsx theme={null}
import { useState } from "react";
import { SegmentedControl } from "@servicetitan/anvil2";
import MenuIcon from "@servicetitan/anvil2/assets/icons/material/round/menu.svg";

const ExampleComponent = () => {
  const [selected, setSelected] = useState("level 2");

  return (
    <Flex direction="column">
      <SegmentedControl selected={selected} onChange={setSelected}>
        <SegmentedControl.Segment value="level 1" icon={MenuIcon}>
          Level 1
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 2" icon={MenuIcon}>
          Level 2
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 3" icon={MenuIcon}>
          Level 3
        </SegmentedControl.Segment>
        <SegmentedControl.Segment value="level 4" icon={MenuIcon}>
          Level 4
        </SegmentedControl.Segment>
      </SegmentedControl>
    </Flex>
  );
};
```

### SegmentedControl components

The Anvil2 segmented control is made up of a `SegmentedControl` component and multiple child `SegmentedControl.Segment` components. Similar to a group of radio inputs, each `SegmentedControl.Segment` will need a unique `value` string that will be passed into the `SegmentedControl`'s `onChange` function when it is selected.

### Tooltip Example

The `SegmentedControl.Segment` components can be wrapped in the Anvil2 `Tooltip.Trigger` component to display a tooltip on focus and hover. This is required for accessibility when only using an icon.

segmentedcontrol-tooltip

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/segmentedcontrol-tooltip?file=src/App.tsx)

```tsx lines expandable theme={null}
import { SegmentedControl, Flex, Tooltip } from "@servicetitan/anvil2";
import AddCircle from "@servicetitan/anvil2/assets/icons/material/round/add_circle.svg";
import BorderClear from "@servicetitan/anvil2/assets/icons/material/round/border_clear.svg";
import ContentCopy from "@servicetitan/anvil2/assets/icons/material/round/content_copy.svg";
import FileUpload from "@servicetitan/anvil2/assets/icons/material/round/file_upload.svg";
import GridView from "@servicetitan/anvil2/assets/icons/material/round/grid_view.svg";
import { useState } from "react";

function App() {
  const [selected, setSelected] = useState("upload");

  return (
    <Flex direction="column">
      <SegmentedControl selected={selected} onChange={setSelected}>
        <Tooltip>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="add"
              icon={AddCircle}
              aria-label="Add"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>Add</Tooltip.Content>
        </Tooltip>

        <Tooltip>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="border"
              icon={BorderClear}
              aria-label="Border"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>Border</Tooltip.Content>
        </Tooltip>

        <Tooltip>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="copy"
              icon={ContentCopy}
              aria-label="Copy"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>Copy</Tooltip.Content>
        </Tooltip>

        <Tooltip defaultOpen>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="upload"
              icon={FileUpload}
              aria-label="Upload"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>Upload</Tooltip.Content>
        </Tooltip>

        <Tooltip>
          <Tooltip.Trigger>
            <SegmentedControl.Segment
              value="grid"
              icon={GridView}
              aria-label="Grid"
            />
          </Tooltip.Trigger>
          <Tooltip.Content>Grid</Tooltip.Content>
        </Tooltip>
      </SegmentedControl>
    </Flex>
  );
}

export default App;
```

**SegmentedControl Props**

```tsx theme={null}
import { SegmentedControl } from "@servicetitan/anvil2";

function ExampleComponent() {
return (

<SegmentedControl
  selected="level-1"
  onChange={(value) => console.log(value)}
  size="medium"
  fill={false}
>
  <SegmentedControl.Segment value="level-1">Level 1</SegmentedControl.Segment>
</SegmentedControl>
); }

```

## `SegmentedControl` Props

In addition to the props listed below, the `SegmentedControl` component can accept any valid HTML `div` props.

**defaultSelected** `string`

Set the default value in uncontrolled uses.

**fill** `boolean` (default: false)

Whether or not to fill the available width.

**name** `string` (default: useId())

Used to add name to segments for control. If empty, it will auto generate one.

**onChange** `(value: string) =\> void`

**selected** `string`

Set the value in controlled uses.

**size** `"small" | "medium"` (default: medium)

Size of the segmented control.

**SegmentedControl.Segment Props**

```tsx theme={null}
import { SegmentedControl } from "@servicetitan/anvil2";

function ExampleComponent() {
  return (
    <SegmentedControl.Segment value="segment-1" icon={MenuIcon}>
      Segment Label
    </SegmentedControl.Segment>
  );
}
```

## `SegmentedControl.Segment` Props

In addition to the props listed below, the `SegmentedControl.Segment` component can accept any valid HTML `label` props.

**value** `string` *required*

A unique identifier for the segment, used to track the selection state.

**icon** `Svg`

Icon to display in the segment (SVGR import).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.