Toggle Group
Zestaw przycisków przełączających do wyboru jednej opcji — albo kilku — z małego, widocznego zbioru.
import {
AlignCenterIcon,
AlignJustifyIcon,
AlignLeftIcon,
AlignRightIcon,
} from "lucide-react"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
export default function ToggleGroupDemo() {
return (
<ToggleGroup
variant="outline"
spacing={0}
defaultValue={["left"]}
aria-label="Wyrównanie tekstu"
>
<ToggleGroupItem value="left" aria-label="Wyrównaj do lewej">
<AlignLeftIcon />
</ToggleGroupItem>
<ToggleGroupItem value="center" aria-label="Wyśrodkuj">
<AlignCenterIcon />
</ToggleGroupItem>
<ToggleGroupItem value="right" aria-label="Wyrównaj do prawej">
<AlignRightIcon />
</ToggleGroupItem>
<ToggleGroupItem value="justify" aria-label="Wyjustuj">
<AlignJustifyIcon />
</ToggleGroupItem>
</ToggleGroup>
)
}Anatomia
- 1GrupaJedna kontrolka i jedno miejsce w kolejności tabulacji: strzałki przenoszą fokus między elementami, a Tab przechodzi dalej. Ustala wariant, rozmiar i odstępy wszystkich elementów.
- 2Wciśnięty elementWybrane opcje mają wypełnienie stanu wciśnięcia i zgłaszają aria-pressed. Grupa może dopuszczać jeden wybór albo kilka.
- 3ElementPrzycisk przełączający. Elementy z samą ikoną potrzebują aria-label, jak każdy przycisk z ikoną.
Instalacja
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/toggle-group.jsonUżycie
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"<ToggleGroup defaultValue={["left"]} aria-label="Text alignment">
<ToggleGroupItem value="left" aria-label="Align left">
<AlignLeftIcon />
</ToggleGroupItem>
<ToggleGroupItem value="center" aria-label="Align center">
<AlignCenterIcon />
</ToggleGroupItem>
</ToggleGroup>Wartość jest zawsze tablicą wartości wciśniętych elementów — ["left"] przy pojedynczym wyborze, ["bold", "italic"] przy kilku.
Przykłady
Wielokrotny wybór
Dodaj multiple, żeby można było wcisnąć naraz dowolną liczbę elementów — jak na pasku formatowania.
import {
BoldIcon,
ItalicIcon,
StrikethroughIcon,
UnderlineIcon,
} from "lucide-react"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
export default function ToggleGroupMultiple() {
return (
<ToggleGroup
multiple
defaultValue={["bold", "italic"]}
aria-label="Styl tekstu"
>
<ToggleGroupItem value="bold" aria-label="Pogrubienie">
<BoldIcon />
</ToggleGroupItem>
<ToggleGroupItem value="italic" aria-label="Kursywa">
<ItalicIcon />
</ToggleGroupItem>
<ToggleGroupItem value="underline" aria-label="Podkreślenie">
<UnderlineIcon />
</ToggleGroupItem>
<ToggleGroupItem value="strikethrough" aria-label="Przekreślenie">
<StrikethroughIcon />
</ToggleGroupItem>
</ToggleGroup>
)
}Kontrolka segmentowa
spacing={0} w połączeniu z wariantem outline scala elementy w jedną kontrolkę ze wspólnymi obramowaniami — kontrolkę segmentową do przełączania między kilkoma widokami tej samej treści.
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
export default function ToggleGroupSegmented() {
return (
<ToggleGroup
variant="outline"
size="sm"
spacing={0}
defaultValue={["week"]}
aria-label="Zakres kalendarza"
>
<ToggleGroupItem value="day">Dzień</ToggleGroupItem>
<ToggleGroupItem value="week">Tydzień</ToggleGroupItem>
<ToggleGroupItem value="month">Miesiąc</ToggleGroupItem>
<ToggleGroupItem value="year">Rok</ToggleGroupItem>
</ToggleGroup>
)
}Przełącznik widoku
W grupie jednokrotnego wyboru ponowne naciśnięcie aktywnego elementu zwalnia go i nic nie zostaje wybrane. Gdy jedna opcja musi być zawsze aktywna, kontroluj wartość i ignoruj puste aktualizacje.
- Atlas
- Beacon
- Cinder
- Delta
"use client"
import * as React from "react"
import { LayoutGridIcon, ListIcon } from "lucide-react"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { cn } from "@/lib/utils"
const projects = ["Atlas", "Beacon", "Cinder", "Delta"]
export default function ToggleGroupViewSwitcher() {
const [view, setView] = React.useState("grid")
return (
<div className="flex w-full max-w-sm flex-col gap-4">
<div className="flex items-center justify-between">
<span id="view-label" className="text-sm font-medium">
Projekty
</span>
<ToggleGroup
variant="outline"
size="sm"
spacing={0}
value={[view]}
// Single selection: ignore attempts to deselect the active view.
onValueChange={(value) => value.length > 0 && setView(value[0])}
aria-labelledby="view-label"
>
<ToggleGroupItem value="grid" aria-label="Widok siatki">
<LayoutGridIcon />
</ToggleGroupItem>
<ToggleGroupItem value="list" aria-label="Widok listy">
<ListIcon />
</ToggleGroupItem>
</ToggleGroup>
</div>
<ul
className={cn(
"grid gap-2",
view === "grid" ? "grid-cols-2" : "grid-cols-1"
)}
>
{projects.map((project) => (
<li
key={project}
className={cn(
"rounded-lg border bg-card px-3 text-sm shadow-raised",
view === "grid"
? "flex h-16 items-end pb-2"
: "flex h-10 items-center"
)}
>
{project}
</li>
))}
</ul>
</div>
)
}const [view, setView] = React.useState("grid")
<ToggleGroup
value={[view]}
onValueChange={(value) => value.length > 0 && setView(value[0])}
aria-label="View"
>
…
</ToggleGroup>Układ pionowy
orientation="vertical" układa elementy jeden pod drugim i przełącza nawigację klawiaturą na strzałki w górę i w dół — to układ palety narzędzi.
import {
MousePointer2Icon,
PenToolIcon,
SquareIcon,
TypeIcon,
} from "lucide-react"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
export default function ToggleGroupVertical() {
return (
<ToggleGroup
orientation="vertical"
defaultValue={["select"]}
aria-label="Narzędzia"
className="rounded-xl border bg-card p-1 shadow-raised"
>
<ToggleGroupItem value="select" aria-label="Zaznaczanie">
<MousePointer2Icon />
</ToggleGroupItem>
<ToggleGroupItem value="pen" aria-label="Pióro">
<PenToolIcon />
</ToggleGroupItem>
<ToggleGroupItem value="shape" aria-label="Prostokąt">
<SquareIcon />
</ToggleGroupItem>
<ToggleGroupItem value="text" aria-label="Tekst">
<TypeIcon />
</ToggleGroupItem>
</ToggleGroup>
)
}Rozmiary
size dotyczy wszystkich elementów: sm 32, default 36, lg 40.
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
const sizes = ["sm", "default", "lg"] as const
export default function ToggleGroupSizes() {
return (
<div className="flex flex-col items-center gap-4">
{sizes.map((size) => (
<ToggleGroup
key={size}
variant="outline"
size={size}
spacing={0}
defaultValue={["monthly"]}
aria-label={`Okres rozliczeniowy (${size})`}
>
<ToggleGroupItem value="monthly">Miesięcznie</ToggleGroupItem>
<ToggleGroupItem value="yearly">Rocznie</ToggleGroupItem>
</ToggleGroup>
))}
</div>
)
}Wytyczne
Kiedy używać
- Do przełączania między dwoma–pięcioma widokami lub trybami tej samej treści: Dzień · Tydzień · Miesiąc, siatka albo lista.
- Na paskach narzędzi z powiązanymi opcjami — jednokrotnego wyboru (wyrównanie) lub wielokrotnego (styl tekstu).
Kiedy nie używać
- Do wyborów w formularzu, który zostanie wysłany później — użyj Radio Group: jest odbierany jako pole formularza i obsługuje opisy.
- Przy więcej niż pięciu–sześciu opcjach albo długich etykietach — użyj Select.
- Do niepowiązanych akcji — użyj Button Group. Grupa przycisków przełączających sugeruje wspólny stan.
- Do przełączania widoków, z których każdy ma własny panel — użyj Tabs. Do nawigacji między stronami służą linki.
Krótkie i jednorodne etykiety
Segmenty powinny być tego samego rodzaju i mieć zbliżoną długość — wtedy kontrolka jest odbierana jako jeden zestaw. Ikony sprawdzają się na paskach narzędzi; przy trybach lepiej działają słowa.
Dostępność
- Grupa renderuje
role="group"; nazwij ją przezaria-labelalboaria-labelledbywskazujące widoczną etykietę. - Każdy element to przycisk przełączający z
aria-pressed. Elementy z samą ikoną potrzebująaria-label. - Grupa zajmuje jedno miejsce w kolejności tabulacji, a fokus wędruje w jej obrębie (roving focus): Tab przenosi fokus do grupy, strzałki przesuwają go między elementami, a na końcach fokus przeskakuje na przeciwny koniec grupy (
loopFocus).
| Klawisz | Działanie |
|---|---|
Tab | Przenosi fokus do grupy; kolejne naciśnięcie ją opuszcza. |
→↓ | Przenosi fokus na następny element (w grupach pionowych — w dół). |
←↑ | Przenosi fokus na poprzedni element (w grupach pionowych — w górę). |
SpacjaEnter | Wciska lub zwalnia element, na którym jest fokus. |
Dokumentacja API
ToggleGroup
Renderuje <div> z role="group". Przyjmuje wszystkie propsy komponentu Toggle Group z Base UI.
ToggleGroupItem
Toggle, który zgłasza grupie swoje value. Renderuje <button>.