# SegmentedControl

SegmentedControl is a horizontal control made up of multiple segments or
options, which adjusts the presentation of a single view. A common use case is
for swapping between Day/Week/Month views in a calendar. The same content is
displayed, however the presentation changes based on the selected segment.

## Design & usage guidelines

SegmentedControl should only use up to five options with succinct labels. The
component will also grow quite wide with more options and can become unusable on
smaller screens. In that case, it is advised to put the SegmentedControl in a
parent container with a fixed width. Be sure to avoid truncating the labels.

## Content guidelines

Concise [Text](../Text/Text.md) should be used as the primary format for option
labels.

```tsx
import React from "react";
import { SegmentedControl } from "@jobber/components/SegmentedControl";

export function SegmentedControlContentGuidelinesExample() {
  return (
    <SegmentedControl defaultValue="option1">
      <SegmentedControl.Option value="option1">
        Option 1
      </SegmentedControl.Option>
      <SegmentedControl.Option value="option2">
        Option 2
      </SegmentedControl.Option>
      <SegmentedControl.Option value="option3">
        Option 3
      </SegmentedControl.Option>
      <SegmentedControl.Option value="option4">
        Option 4
      </SegmentedControl.Option>
      <SegmentedControl.Option value="option5">
        Option 5
      </SegmentedControl.Option>
    </SegmentedControl>
  );
}
```

Using [Icons](../Icon/Icon.md) as labels should only be used if the icon has
been tested as understandable in isolation.

```tsx
import React from "react";
import { SegmentedControl } from "@jobber/components/SegmentedControl";
import { Icon } from "@jobber/components/Icon";

export function SegmentedControlIconsExample() {
  return (
    <SegmentedControl defaultValue="calendar">
      <SegmentedControl.Option value="calendar">
        <Icon name="calendar" />
      </SegmentedControl.Option>
      <SegmentedControl.Option value="phone">
        <Icon name="phone" />
      </SegmentedControl.Option>
      <SegmentedControl.Option value="availability">
        <Icon name="availability" />
      </SegmentedControl.Option>
    </SegmentedControl>
  );
}
```

Mixing content types within a single label, like using an icon with text, should
be avoided. This would be an inefficient use of the SegmentedControl's limited
horizontal space.

Mixing content types across options should also be avoided. This would create an
inconsistent experience for users and lead to a jarring visual rhythm.

If you do not have enough horizontal room to allow for readable labels, consider
using [Menu](../Menu/Menu.md) as an alternative single-selection method for
modifying the view. Otherwise, truncation will prevent the user from reading the
label and a label with wrapped text will create layout inconsistencies.

## Related components

Unlike [Tabs](../Tabs/Tabs.md), the contents of each segment are not contained
by each label. You should use Tabs when you need to navigate between related
subgroups of different content.

Unlike [Switch](../Switch/Switch.md), which toggles between a simple On/Off
state, the SegmentedControl offers more than two options.

With SegmentedControl, options are more aggressively grouped than
[Chips](../Chips/Chips.md) and also cannot reflow when it runs out of room.

## Accessibility

When using a screen reader, the SegmentedControl will be read as a group of
options. The `ariaLabel` of the currently selected option will be announced and
also declared as selected.

The user can navigate between options using the arrow keys and a counter will
indicate the current option number, out of the total number of options.

### Keyboard interactions

To enter the SegmentedControl, use the Tab key. Use the left and right arrow
keys to navigate between options. Hitting the Tab key again will exit the
SegmentedControl.


## Controlled & Uncontrolled

### Controlled

Use a
[controlled](/storybook/web/?path=/story/components-selections-segmentedcontrol--controlled)
SegmentedControl when the selected option needs to sync with other application
state or when side effects should occur upon selection changes.

For a controlled SegmentedControl, set the `selectedValue` prop and use
`onSelectValue` as a callback that updates the external state.

```tsx
const [selectedOption, setSelectedOption] = useState("day");

<SegmentedControl
  selectedValue={selectedOption}
  onSelectValue={setSelectedOption}
>
  <SegmentedControl.Option value="day">Day</SegmentedControl.Option>
  <SegmentedControl.Option value="week">Week</SegmentedControl.Option>
  <SegmentedControl.Option value="month">Month</SegmentedControl.Option>
</SegmentedControl>;
```

### Uncontrolled

An
[uncontrolled](/storybook/web/?path=/story/components-selections-segmentedcontrol--uncontrolled)
SegmentedControl manages its selected state internally, which is useful for
simpler use cases where the selected option does not need to sync with other
parts of your application’s state.

Use the `defaultValue` prop to set the initially selected option.

```tsx
<SegmentedControl defaultValue="day">
 <SegmentedControl.Option value="day">Day</SegmentedControl.Option>
 <SegmentedControl.Option value="week">Week</SegmentedControl.Option>
 <SegmentedControl.Option value="month">Month</SegmentedControl.Option>
</SegmentedControl.Option>
```

## Developer notes

SegmentedControl does not have any specific arrow key logic. That is because
arrow key navigation is implicitly set through the SegmentedControl radio button
structure. The options are a type of `radio` and part of a group (`name`
attribute) which inherently supports keyboard navigation.

Because the component uses a `role="radiogroup"` and `name` attribute, the
browser handles this behaviour automatically.


## Props

### Web

#### SegmentedControl

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `defaultValue` | `T` | No | — | The default option to be selected initially. Set this prop when the component is uncontrolled. |
| `name` | `string` | No | `useId()` | A unique name for the SegmentedControl, that links the group of options together. Can be a string or, if not set, wil... |
| `onSelectValue` | `(value: T) => void` | No | — | A callback function that is called whenever the selected option changes. Use this prop with `selectedValue` for a con... |
| `selectedValue` | `T` | No | — | The currently selected option. Use this prop with `onSelectValue` for a controlled component. |
| `size` | `"base" | "large" | "small"` | No | `base` | Adjusts the size of the SegmentedControl. The default size is "base". |

#### SegmentedControl.Option

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `value` | `number | string` | Yes | — | The unique value associated with this option. This value is used to determine which option is selected and is passed ... |
| `ariaLabel` | `string` | No | — | An aria-label that describes the option. |
