Search for a command to run...
A set of two-state buttons that can be toggled on or off.
npx shadcn@latest add @zaidan/toggle-grouppnpx shadcn add @zaidan/toggle-groupyarn dlx shadcn@latest add @zaidan/toggle-groupbunx shadcn@latest add @zaidan/toggle-groupInstall the following dependencies:
npm i @kobalte/corepnpm add @kobalte/coreyarn add @kobalte/corebun add @kobalte/coreCopy and paste the following code into your project.
1import type { PolymorphicProps } from "@kobalte/core/polymorphic";2import {3 type ToggleGroupItemProps,4 ToggleGroup as ToggleGroupPrimitive,5 type ToggleGroupRootProps,6} from "@kobalte/core/toggle-group";7import type { VariantProps } from "class-variance-authority";8import {9 type ComponentProps,10 createContext,11 type JSX,12 mergeProps,13 splitProps,14 useContext,15 type ValidComponent,16} from "solid-js";17import { cn } from "~/lib/utils";18import { toggleVariants } from "~/components/ui/toggle";19
20type ToggleGroupContextValue = VariantProps<typeof toggleVariants> & {21 spacing?: number;22 orientation?: "horizontal" | "vertical";23};24
25const ToggleGroupContext = createContext<ToggleGroupContextValue>({26 size: "default",27 variant: "default",28 spacing: 0,29 orientation: "horizontal",30});31
32type ToggleGroupProps<T extends ValidComponent = "div"> = PolymorphicProps<33 T,34 ToggleGroupRootProps<T>35> &36 Pick<ComponentProps<T>, "class" | "children"> &37 VariantProps<typeof toggleVariants> & {38 spacing?: number;39 orientation?: "horizontal" | "vertical";40 };41
42const ToggleGroup = <T extends ValidComponent = "div">(rawProps: ToggleGroupProps<T>) => {43 const props = mergeProps(44 {45 spacing: 0,46 orientation: "horizontal",47 } as const,48 rawProps,49 );50 const [local, others] = splitProps(props as ToggleGroupProps, [51 "class",52 "children",53 "variant",54 "size",55 "spacing",56 "orientation",57 ]);58
59 return (60 <ToggleGroupPrimitive61 data-slot="toggle-group"62 data-variant={local.variant}63 data-size={local.size}64 data-spacing={local.spacing}65 data-orientation={local.orientation}66 style={{ "--gap": local.spacing } as JSX.CSSProperties}67 class={cn(68 "group/toggle-group z-toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch",69 local.class,70 )}71 {...others}72 >73 <ToggleGroupContext.Provider74 value={{75 variant: local.variant,76 size: local.size,77 spacing: local.spacing,78 orientation: local.orientation,79 }}80 >81 {local.children}82 </ToggleGroupContext.Provider>83 </ToggleGroupPrimitive>84 );85};86
87type ToggleGroupItemComponentProps<T extends ValidComponent = "button"> = PolymorphicProps<88 T,89 ToggleGroupItemProps<T>90> &91 VariantProps<typeof toggleVariants> &92 Pick<ComponentProps<T>, "class" | "children">;93
94const ToggleGroupItem = <T extends ValidComponent = "button">(95 rawProps: ToggleGroupItemComponentProps<T>,96) => {97 const props = mergeProps({ variant: "default" as const, size: "default" as const }, rawProps);98 const [local, others] = splitProps(props as ToggleGroupItemComponentProps, [99 "class",100 "children",101 "variant",102 "size",103 ]);104 const context = useContext(ToggleGroupContext);105
106 return (107 <ToggleGroupPrimitive.Item108 data-slot="toggle-group-item"109 data-variant={context.variant || local.variant}110 data-size={context.size || local.size}111 data-spacing={context.spacing}112 class={cn(113 toggleVariants({114 variant: context.variant || local.variant,115 size: context.size || local.size,116 class:117 "z-toggle-group-item shrink-0 focus:z-10 focus-visible:z-10 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l",118 }),119 local.class,120 )}121 {...others}122 >123 {local.children}124 </ToggleGroupPrimitive.Item>125 );126};127
128export { ToggleGroup, ToggleGroupItem, type ToggleGroupProps };Here are the source code of all the examples from the preview page:
import { Bold, Italic, Underline } from "lucide-solid";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupBasic() { return ( <Example title="Basic"> <ToggleGroup multiple spacing={1}> <ToggleGroupItem value="bold" aria-label="Toggle bold"> <Bold /> </ToggleGroupItem> <ToggleGroupItem value="italic" aria-label="Toggle italic"> <Italic /> </ToggleGroupItem> <ToggleGroupItem value="underline" aria-label="Toggle underline"> <Underline /> </ToggleGroupItem> </ToggleGroup> </Example> );}import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupOutline() { return ( <Example title="Outline"> <ToggleGroup multiple={false} variant="outline" defaultValue="all"> <ToggleGroupItem value="all" aria-label="Toggle all"> All </ToggleGroupItem> <ToggleGroupItem value="missed" aria-label="Toggle missed"> Missed </ToggleGroupItem> </ToggleGroup> </Example> );}import { Bold, Italic, Underline } from "lucide-solid";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupOutlineWithIcons() { return ( <Example title="Outline With Icons"> <ToggleGroup variant="outline" multiple size="sm"> <ToggleGroupItem value="bold" aria-label="Toggle bold"> <Bold /> </ToggleGroupItem> <ToggleGroupItem value="italic" aria-label="Toggle italic"> <Italic /> </ToggleGroupItem> <ToggleGroupItem value="underline" aria-label="Toggle underline"> <Underline /> </ToggleGroupItem> </ToggleGroup> </Example> );}import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupSizes() { return ( <Example title="Sizes"> <div class="flex flex-col gap-4"> <ToggleGroup multiple={false} size="sm" defaultValue="top" variant="outline"> <ToggleGroupItem value="top" aria-label="Toggle top"> Top </ToggleGroupItem> <ToggleGroupItem value="bottom" aria-label="Toggle bottom"> Bottom </ToggleGroupItem> <ToggleGroupItem value="left" aria-label="Toggle left"> Left </ToggleGroupItem> <ToggleGroupItem value="right" aria-label="Toggle right"> Right </ToggleGroupItem> </ToggleGroup> <ToggleGroup multiple={false} defaultValue="top" variant="outline"> <ToggleGroupItem value="top" aria-label="Toggle top"> Top </ToggleGroupItem> <ToggleGroupItem value="bottom" aria-label="Toggle bottom"> Bottom </ToggleGroupItem> <ToggleGroupItem value="left" aria-label="Toggle left"> Left </ToggleGroupItem> <ToggleGroupItem value="right" aria-label="Toggle right"> Right </ToggleGroupItem> </ToggleGroup> </div> </Example> );}Use spacing={2} to add spacing between toggle group items.
import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupSpacing() { return ( <Example title="With Spacing"> <ToggleGroup multiple={false} size="sm" defaultValue="top" variant="outline" spacing={2}> <ToggleGroupItem value="top" aria-label="Toggle top"> Top </ToggleGroupItem> <ToggleGroupItem value="bottom" aria-label="Toggle bottom"> Bottom </ToggleGroupItem> <ToggleGroupItem value="left" aria-label="Toggle left"> Left </ToggleGroupItem> <ToggleGroupItem value="right" aria-label="Toggle right"> Right </ToggleGroupItem> </ToggleGroup> </Example> );}import { Bookmark, Heart, Star } from "lucide-solid";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupWithIcons() { return ( <Example title="With Icons"> <ToggleGroup multiple variant="outline" spacing={2} size="sm"> <ToggleGroupItem value="star" aria-label="Toggle star" class="aria-pressed:bg-transparent aria-pressed:*:[svg]:fill-foreground aria-pressed:*:[svg]:stroke-foreground" > <Star /> Star </ToggleGroupItem> <ToggleGroupItem value="heart" aria-label="Toggle heart" class="aria-pressed:bg-transparent aria-pressed:*:[svg]:fill-foreground aria-pressed:*:[svg]:stroke-foreground" > <Heart /> Heart </ToggleGroupItem> <ToggleGroupItem value="bookmark" aria-label="Toggle bookmark" class="aria-pressed:bg-transparent aria-pressed:*:[svg]:fill-foreground aria-pressed:*:[svg]:stroke-foreground" > <Bookmark /> Bookmark </ToggleGroupItem> </ToggleGroup> </Example> );}import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupFilter() { return ( <Example title="Filter"> <ToggleGroup multiple={false} defaultValue="all" variant="outline" size="sm"> <ToggleGroupItem value="all" aria-label="All"> All </ToggleGroupItem> <ToggleGroupItem value="active" aria-label="Active"> Active </ToggleGroupItem> <ToggleGroupItem value="completed" aria-label="Completed"> Completed </ToggleGroupItem> <ToggleGroupItem value="archived" aria-label="Archived"> Archived </ToggleGroupItem> </ToggleGroup> </Example> );}import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupDateRange() { return ( <Example title="Date Range"> <ToggleGroup multiple={false} defaultValue="today" variant="outline" size="sm" spacing={2}> <ToggleGroupItem value="today" aria-label="Today"> Today </ToggleGroupItem> <ToggleGroupItem value="week" aria-label="This Week"> This Week </ToggleGroupItem> <ToggleGroupItem value="month" aria-label="This Month"> This Month </ToggleGroupItem> <ToggleGroupItem value="year" aria-label="This Year"> This Year </ToggleGroupItem> </ToggleGroup> </Example> );}import { ArrowDown, ArrowUp, TrendingUp } from "lucide-solid";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupSort() { return ( <Example title="Sort"> <ToggleGroup multiple={false} defaultValue="newest" variant="outline" size="sm"> <ToggleGroupItem value="newest" aria-label="Newest"> <ArrowDown /> Newest </ToggleGroupItem> <ToggleGroupItem value="oldest" aria-label="Oldest"> <ArrowUp /> Oldest </ToggleGroupItem> <ToggleGroupItem value="popular" aria-label="Popular"> <TrendingUp /> Popular </ToggleGroupItem> </ToggleGroup> </Example> );}import { Input } from "~/components/ui/input";import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "~/components/ui/select";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupWithInputAndSelect() { const items = [ { label: "All", value: "all" }, { label: "Active", value: "active" }, { label: "Archived", value: "archived" }, ]; return ( <Example title="With Input and Select"> <div class="flex items-center gap-2"> <Input type="search" placeholder="Search..." class="flex-1" /> <Select options={items} optionValue="value" optionTextValue="label" defaultValue={items[0]} itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger class="w-32"> <SelectValue<(typeof items)[number]>> {(state) => state.selectedOption().label} </SelectValue> </SelectTrigger> <SelectContent /> </Select> <ToggleGroup multiple={false} defaultValue="grid" variant="outline"> <ToggleGroupItem value="grid" aria-label="Grid view"> Grid </ToggleGroupItem> <ToggleGroupItem value="list" aria-label="List view"> List </ToggleGroupItem> </ToggleGroup> </div> </Example> );}import { Bold, Italic, Underline } from "lucide-solid";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupVertical() { return ( <Example title="Vertical"> <ToggleGroup multiple orientation="vertical" spacing={1}> <ToggleGroupItem value="bold" aria-label="Toggle bold"> <Bold /> </ToggleGroupItem> <ToggleGroupItem value="italic" aria-label="Toggle italic"> <Italic /> </ToggleGroupItem> <ToggleGroupItem value="underline" aria-label="Toggle underline"> <Underline /> </ToggleGroupItem> </ToggleGroup> </Example> );}import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupVerticalOutline() { return ( <Example title="Vertical Outline"> <ToggleGroup multiple={false} variant="outline" defaultValue="all" orientation="vertical" size="sm" > <ToggleGroupItem value="all" aria-label="Toggle all"> All </ToggleGroupItem> <ToggleGroupItem value="active" aria-label="Toggle active"> Active </ToggleGroupItem> <ToggleGroupItem value="completed" aria-label="Toggle completed"> Completed </ToggleGroupItem> <ToggleGroupItem value="archived" aria-label="Toggle archived"> Archived </ToggleGroupItem> </ToggleGroup> </Example> );}import { Bold, Italic, Underline } from "lucide-solid";import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupVerticalOutlineWithIcons() { return ( <Example title="Vertical Outline With Icons"> <ToggleGroup variant="outline" multiple orientation="vertical" size="sm"> <ToggleGroupItem value="bold" aria-label="Toggle bold"> <Bold /> </ToggleGroupItem> <ToggleGroupItem value="italic" aria-label="Toggle italic"> <Italic /> </ToggleGroupItem> <ToggleGroupItem value="underline" aria-label="Toggle underline"> <Underline /> </ToggleGroupItem> </ToggleGroup> </Example> );}import { ToggleGroup, ToggleGroupItem } from "~/components/ui/toggle-group";function ToggleGroupVerticalWithSpacing() { return ( <Example title="Vertical With Spacing"> <ToggleGroup multiple={false} size="sm" defaultValue="top" variant="outline" orientation="vertical" spacing={1} > <ToggleGroupItem value="top" aria-label="Toggle top"> Top </ToggleGroupItem> <ToggleGroupItem value="bottom" aria-label="Toggle bottom"> Bottom </ToggleGroupItem> <ToggleGroupItem value="left" aria-label="Toggle left"> Left </ToggleGroupItem> <ToggleGroupItem value="right" aria-label="Toggle right"> Right </ToggleGroupItem> </ToggleGroup> </Example> );}The main wrapper component for toggle group items.
| Prop | Type | Default |
|---|---|---|
multiple | boolean | false |
variant | "default" | "outline" | "default" |
size | "default" | "sm" | "lg" | "default" |
spacing | number | 0 |
orientation | "horizontal" | "vertical" | "horizontal" |
defaultValue | string | string[] | - |
value | string | string[] | - |
onChange | (value: string | string[]) => void | - |
disabled | boolean | false |
class | string | - |
Individual toggle elements within a group. Include an aria-label on each item for accessibility purposes.
| Prop | Type | Default |
|---|---|---|
value | string | Required |
disabled | boolean | false |
class | string | - |