Primitives
Toggle Group
A row of toggles that share one value.
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
export default function ToggleGroupHero() {
return (
<ToggleGroup type="single" variant="outline" defaultValue="30" aria-label="Period of the report">
<ToggleGroupItem value="7">7 days</ToggleGroupItem>
<ToggleGroupItem value="30">30 days</ToggleGroupItem>
<ToggleGroupItem value="90">90 days</ToggleGroupItem>
</ToggleGroup>
)
}Import the two parts. The type prop of the group and the value prop of each item are required.
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
<ToggleGroup type="single">
<ToggleGroupItem />
</ToggleGroup>| Part | Role |
|---|---|
ToggleGroup | Holds the value. It gives its variant and its size to each item. |
ToggleGroupItem | One option. Its value identifies it. |
The type prop sets how many items the user can press.
| Type | Value | Use |
|---|---|---|
single | A string | One option of a set: a view, a period, an alignment. |
multiple | An array of strings | Options that do not depend on each other. |
The group holds its value by default. Use defaultValue to set it at the start. To control the value, pass value and onValueChange.
value: ["bold"]
import * as React from 'react'
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
import { Bold, Italic, Underline } from 'lucide-react'
export default function ToggleGroupMultiple() {
const [formats, setFormats] = React.useState(['bold'])
return (
<div className="flex flex-col items-center gap-3">
<ToggleGroup type="multiple" variant="outline" aria-label="Text format" value={formats} onValueChange={setFormats}>
<ToggleGroupItem value="bold" aria-label="Bold">
<Bold />
</ToggleGroupItem>
<ToggleGroupItem value="italic" aria-label="Italic">
<Italic />
</ToggleGroupItem>
<ToggleGroupItem value="underline" aria-label="Underline">
<Underline />
</ToggleGroupItem>
</ToggleGroup>
<p className="font-mono text-xs text-foreground-lighter">value: {JSON.stringify(formats)}</p>
</div>
)
}With type="single", a click on the pressed item sends an empty string. If one item must stay pressed, ignore the empty value in onValueChange.
import * as React from 'react'
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
import { LayoutGrid, List } from 'lucide-react'
const PROJECTS = ['Customer portal', 'Marketing site', 'Mobile app', 'Billing portal']
export default function ToggleGroupRequired() {
const [view, setView] = React.useState('grid')
return (
<div className="flex w-full max-w-sm flex-col gap-3">
<ToggleGroup
type="single"
variant="outline"
aria-label="View"
value={view}
// A click on the pressed item sends "". Ignore it to keep one item pressed.
onValueChange={(next) => next && setView(next)}
>
<ToggleGroupItem value="grid" aria-label="Grid view">
<LayoutGrid />
</ToggleGroupItem>
<ToggleGroupItem value="list" aria-label="List view">
<List />
</ToggleGroupItem>
</ToggleGroup>
<ul className={view === 'grid' ? 'grid grid-cols-2 gap-2' : 'flex flex-col gap-2'}>
{PROJECTS.map((project) => (
<li key={project} className="rounded-md border bg-surface-100 px-3 py-2 text-[13px] text-foreground">
{project}
</li>
))}
</ul>
</div>
)
}The variant prop of the group sets the look of each item.
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
export default function ToggleGroupVariants() {
return (
<>
<ToggleGroup type="single" defaultValue="month" aria-label="Billing period, default variant">
<ToggleGroupItem value="month">Monthly</ToggleGroupItem>
<ToggleGroupItem value="year">Yearly</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" variant="outline" defaultValue="month" aria-label="Billing period, outline variant">
<ToggleGroupItem value="month">Monthly</ToggleGroupItem>
<ToggleGroupItem value="year">Yearly</ToggleGroupItem>
</ToggleGroup>
</>
)
}| Variant | Look |
|---|---|
default | Items with no border. |
outline | One control with a border. |
The size prop of the group sets the height of each item.
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
const SIZES = ['tiny', 'sm', 'md'] as const
export default function ToggleGroupSizes() {
return (
<>
{SIZES.map((size) => (
<ToggleGroup key={size} type="single" variant="outline" size={size} defaultValue="grid" aria-label={`View, size ${size}`}>
<ToggleGroupItem value="grid">Grid</ToggleGroupItem>
<ToggleGroupItem value="list">List</ToggleGroupItem>
</ToggleGroup>
))}
</>
)
}| Size | Height |
|---|---|
tiny | 26px |
sm | 30px (default) |
md | 34px |
By default, the items make one control. Pass spacing to put a gap between them. One unit is 4px.
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
export default function ToggleGroupSpacing() {
return (
<ToggleGroup type="multiple" variant="outline" spacing={2} defaultValue={['email']} aria-label="Notification channels">
<ToggleGroupItem value="email">Email</ToggleGroupItem>
<ToggleGroupItem value="sms">SMS</ToggleGroupItem>
<ToggleGroupItem value="push">Push</ToggleGroupItem>
</ToggleGroup>
)
}Set disabled on one item or on the group.
import { ToggleGroup, ToggleGroupItem } from 'ferry-ui'
export default function ToggleGroupDisabled() {
return (
<>
<ToggleGroup type="single" variant="outline" defaultValue="month" aria-label="Billing period">
<ToggleGroupItem value="month">Monthly</ToggleGroupItem>
<ToggleGroupItem value="year">Yearly</ToggleGroupItem>
<ToggleGroupItem value="lifetime" disabled>
Lifetime
</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" variant="outline" defaultValue="month" disabled aria-label="Billing period, disabled">
<ToggleGroupItem value="month">Monthly</ToggleGroupItem>
<ToggleGroupItem value="year">Yearly</ToggleGroupItem>
</ToggleGroup>
</>
)
}Give the group an aria-label. For a label that the user sees, put the group in a Field with labelAs="span".
The system option follows the theme of the device.
import { Field, ToggleGroup, ToggleGroupItem } from 'ferry-ui'
import { Monitor, Moon, Sun } from 'lucide-react'
export default function ToggleGroupField() {
return (
<Field label="Theme" labelAs="span" hint="The system option follows the theme of the device.">
<ToggleGroup type="single" variant="outline" defaultValue="system">
<ToggleGroupItem value="light">
<Sun /> Light
</ToggleGroupItem>
<ToggleGroupItem value="dark">
<Moon /> Dark
</ToggleGroupItem>
<ToggleGroupItem value="system">
<Monitor /> System
</ToggleGroupItem>
</ToggleGroup>
</Field>
)
}aria-label. For a tooltip, wrap the item in Hint.Each part also accepts the props of its Radix UI primitive and the attributes of its element.
| Prop | Type | Default |
|---|---|---|
typeRequired | "multiple" | "single" | - |
| See the element or the Radix UI primitive this part renders. | ||
variant | "default" | "outline" | - |
| ||
size | "default" | "tiny" | "sm" | "md" | "lg" | - |
Item height, on the | ||
spacing | number | 0 |
Gap between items in Tailwind spacing units (1 = 4px). | ||
value | string | string[] | - |
The controlled stateful value of the item that is pressed. The controlled stateful value of the items that are pressed. | ||
defaultValue | string | string[] | - |
The value of the item that is pressed when initially rendered. Use | ||
onValueChange | ((value: string) => void) | ((value: string[]) => void) | - |
The callback that fires when the value of the toggle group changes. The callback that fires when the state of the toggle group changes. | ||
disabled | boolean | false |
Whether the group is disabled from user interaction. | ||
rovingFocus | boolean | true |
Whether the group should maintain roving focus of its buttons. | ||
loop | boolean | - |
| See the element or the Radix UI primitive this part renders. | ||
orientation | "horizontal" | "vertical" | - |
| See the element or the Radix UI primitive this part renders. | ||
dir | "ltr" | "rtl" | - |
| See the element or the Radix UI primitive this part renders. | ||
asChild | boolean | - |
| See the element or the Radix UI primitive this part renders. | ||
value is a required string.
| Prop | Type | Default |
|---|---|---|
valueRequired | string | - |
A string value for the toggle group item. All items within a toggle group should use a unique value. | ||
variant | "default" | "outline" | - |
| ||
size | "default" | "tiny" | "sm" | "md" | "lg" | - |
Item height, on the | ||
asChild | boolean | - |
| See the element or the Radix UI primitive this part renders. | ||