Files
supabase/apps/design-system/content/docs/components/toggle-group.mdx
kemal.earthandGildas Garcia 0e6fff6760 feat(design-system): segmented controls (#50738)
## Problem

We don't have any one defined way of displaying segmented controls. This
PR looks at unifying and using underlying primtives to put something
together. Open to comment.

## Solution

Improves upon the shadcn toggle group, which has a specific use case.

## Review instructions

Run the design system and find "Segmented Controls" in the Fragment
Components. Test
[here](https://design-system-git-feat-button-group-component-draft-supabase.vercel.app/design-system/docs/components/toggle-group#segmented).


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary

* **New Features**
* Added segmented toggle groups with default, text, outline, and primary
tones.
* Single-select groups display a sliding selection indicator;
multi-select groups highlight selected items individually.
* Groups can keep the selected option active; deselection is enabled by
default.
  * Added examples for tone variations and a status filter.
* **Documentation**
* Updated segmented-control guidance and props tables, including usage
recommendations, accessibility labeling, and filter options.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-09-25 11:26:46 +01:00

126 lines
5.1 KiB
Plaintext

---
title: Toggle Group
description: A set of two-state buttons that can be toggled on or off.
component: true
links:
doc: https://www.radix-ui.com/docs/primitives/components/toggle-group
api: https://www.radix-ui.com/docs/primitives/components/toggle-group#api-reference
source:
radix: true
shadcn: true
---
<ComponentPreview name="toggle-group-demo" peekCode wide />
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn-ui@latest add toggle-group
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install the following dependencies:</Step>
```bash
npm install @radix-ui/react-toggle-group
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="toggle-group" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
```
```tsx
<ToggleGroup type="single">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b">B</ToggleGroupItem>
<ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup>
```
## Examples
### Default
<ComponentPreview name="toggle-group-demo" peekCode wide />
### Outline
<ComponentPreview name="toggle-group-outline" />
### Single
<ComponentPreview name="toggle-group-single" />
### Small
<ComponentPreview name="toggle-group-sm" />
### Large
<ComponentPreview name="toggle-group-lg" />
### Disabled
<ComponentPreview name="toggle-group-disabled" />
## Segmented
A Supabase addition, not part of shadcn or Radix. A segmented control is a compact row of two to
four mutually exclusive options sharing one continuous track, for switching view state (Data or
Definition) or filtering a list (All, Active, Revoked). The choice takes effect immediately and is
never saved, so reach for a [Switch](../components/switch) or
[Radio Group](../components/radio-group) when the setting is persisted, and
[Tabs](../components/tabs) when the options swap whole panels of content. Items paint nothing
themselves; a single indicator slides between them, so the group always has exactly one thing
selected. Give a filter an explicit **All** segment rather than letting deselection stand for
"no filter".
<ComponentPreview name="toggle-group-segmented" />
<ComponentPreview name="toggle-group-segmented-filter" peekCode />
## Props
`ToggleGroup` forwards every prop to the underlying
[Radix Toggle Group](https://www.radix-ui.com/docs/primitives/components/toggle-group#api-reference).
These are the ones worth knowing about.
| Prop | Type | Default | Description |
| --------------- | --------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type` | `'single' \| 'multiple'` | | Required by Radix. Only a `'single'` group gets the segmented indicator; a `'multiple'` group falls back to items painting their own background. |
| `variant` | `'default' \| 'outline' \| 'segmented'` | `'default'` | Styles the root and every item, which inherit it through context. `segmented` drops the gaps and per-item borders in favor of an indicator that slides between segments, respecting `prefers-reduced-motion`. |
| `size` | `'tiny' \| 'sm' \| 'default' \| 'lg'` | `'default'` | Item height and padding, inherited through context. `tiny` suits a dense toolbar or table footer. Segments hug their labels, so add `className="flex-1"` to each item, plus a width on the root, if you need them equal. |
| `tone` | `'text' \| 'outline' \| 'primary'` | `'text'` | Segmented only. `text` is a flat `bg-accent` fill, `outline` adds a container border and a raised bordered indicator, `primary` fills the indicator with brand. |
| `allowDeselect` | `boolean` | `true` | Whether clicking the active item in a `type="single"` group clears it, emitting `''`. Set `false` for a segmented control, which has no empty state. |
| `aria-label` | `string` | | Names what is being switched or filtered. The segments name the options, not the axis. |
`variant` and `size` are the shadcn variant axes; `segmented`, `tone` and `allowDeselect` are the
Supabase additions. `default` and `outline` are unchanged from shadcn.