Zaidan

Command Palette

Search for a command to run...

GitHub

Toggle Group

A set of two-state buttons that can be toggled on or off.

Installation

CLI

Manual

Install the following dependencies:

Copy and paste the following code into your project.

import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import {
type ToggleGroupItemProps,
ToggleGroup as ToggleGroupPrimitive,
type ToggleGroupRootProps,
} from "@kobalte/core/toggle-group";
import type { VariantProps } from "class-variance-authority";
import {
type ComponentProps,
createContext,
type JSX,
mergeProps,
splitProps,
useContext,
type ValidComponent,
} from "solid-js";
import { cn } from "~/lib/utils";
import { toggleVariants } from "~/components/ui/toggle";
type ToggleGroupContextValue = VariantProps<typeof toggleVariants> & {
spacing?: number;
orientation?: "horizontal" | "vertical";
};
const ToggleGroupContext = createContext<ToggleGroupContextValue>({
size: "default",
variant: "default",
spacing: 0,
orientation: "horizontal",
});
type ToggleGroupProps<T extends ValidComponent = "div"> = PolymorphicProps<
T,
ToggleGroupRootProps<T>
> &
Pick<ComponentProps<T>, "class" | "children"> &
VariantProps<typeof toggleVariants> & {
spacing?: number;
orientation?: "horizontal" | "vertical";
};
const ToggleGroup = <T extends ValidComponent = "div">(rawProps: ToggleGroupProps<T>) => {
const props = mergeProps(
{
spacing: 0,
orientation: "horizontal",
} as const,
rawProps,
);
const [local, others] = splitProps(props as ToggleGroupProps, [
"class",
"children",
"variant",
"size",
"spacing",
"orientation",
]);
return (
<ToggleGroupPrimitive
data-slot="toggle-group"
data-variant={local.variant}
data-size={local.size}
data-spacing={local.spacing}
data-orientation={local.orientation}
style={{ "--gap": local.spacing } as JSX.CSSProperties}
class={cn(
"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",
local.class,
)}
{...others}
>
<ToggleGroupContext.Provider
value={{
variant: local.variant,
size: local.size,
spacing: local.spacing,
orientation: local.orientation,
}}
>
{local.children}
</ToggleGroupContext.Provider>
</ToggleGroupPrimitive>
);
};
type ToggleGroupItemComponentProps<T extends ValidComponent = "button"> = PolymorphicProps<
T,
ToggleGroupItemProps<T>
> &
VariantProps<typeof toggleVariants> &
Pick<ComponentProps<T>, "class" | "children">;
const ToggleGroupItem = <T extends ValidComponent = "button">(
rawProps: ToggleGroupItemComponentProps<T>,
) => {
const props = mergeProps({ variant: "default" as const, size: "default" as const }, rawProps);
const [local, others] = splitProps(props as ToggleGroupItemComponentProps, [
"class",
"children",
"variant",
"size",
]);
const context = useContext(ToggleGroupContext);
return (
<ToggleGroupPrimitive.Item
data-slot="toggle-group-item"
data-variant={context.variant || local.variant}
data-size={context.size || local.size}
data-spacing={context.spacing}
class={cn(
toggleVariants({
variant: context.variant || local.variant,
size: context.size || local.size,
class:
"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",
}),
local.class,
)}
{...others}
>
{local.children}
</ToggleGroupPrimitive.Item>
);
};
export { ToggleGroup, ToggleGroupItem, type ToggleGroupProps };

Examples

Here are the source code of all the examples from the preview page:

Basic

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>
);
}

Outline

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>
);
}

Outline With Icons

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>
);
}

Sizes

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>
);
}

With Spacing

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>
);
}

With Icons

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>
);
}

Filter

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>
);
}

Date Range

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>
);
}

Sort

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>
);
}

With Input and Select

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>
);
}

Vertical

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>
);
}

Vertical Outline

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>
);
}

Vertical Outline With Icons

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>
);
}

Vertical With Spacing

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>
);
}

API Reference

ToggleGroup

The main wrapper component for toggle group items.

PropTypeDefault
multiplebooleanfalse
variant"default" | "outline""default"
size"default" | "sm" | "lg""default"
spacingnumber0
orientation"horizontal" | "vertical""horizontal"
defaultValuestring | string[]-
valuestring | string[]-
onChange(value: string | string[]) => void-
disabledbooleanfalse
classstring-

ToggleGroupItem

Individual toggle elements within a group. Include an aria-label on each item for accessibility purposes.

PropTypeDefault
valuestringRequired
disabledbooleanfalse
classstring-