Installation
Install the dependencies
pnpm add cn class-variance-authority github:sveltery/baseCopy the component
Copy the following files into src/lib/components/ui/toggle-group.
It imports the toggle component, so copy its folder too.
<script lang="ts">
import { ToggleGroup as Primitive } from '@sveltery/base/toggle-group';
import { cn } from 'cn';
import { setToggleGroupContext } from './context.js';
import type { ToggleGroupProps } from './types.js';
let { value = $bindable(), class: classProp, variant, size, spacing = 2, orientation = 'horizontal', style, children, ...props }: ToggleGroupProps = $props();
setToggleGroupContext({
get variant() { return variant; },
get size() { return size; },
get spacing() { return spacing; },
get orientation() { return orientation; },
});
</script>
<Primitive
data-slot="toggle-group"
data-variant={variant}
data-size={size}
data-spacing={spacing}
data-orientation={orientation}
style="--gap: {spacing};{style ?? ''}"
{orientation}
bind:value
{...props}
class={cn('rounded-lg data-[size=sm]:rounded-[min(var(--radius-md),10px)] group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] data-vertical:flex-col data-vertical:items-stretch', classProp)}
>
{@render children?.()}
</Primitive><script lang="ts">
import { Toggle as Primitive } from '@sveltery/base/toggle';
import { cn } from 'cn';
import { toggleVariants } from '../toggle/index.js';
import { getToggleGroupContext } from './context.js';
import type { ToggleGroupItemProps } from './types.js';
let { class: classProp, variant = 'default', size = 'default', ...props }: ToggleGroupItemProps = $props();
const group = getToggleGroupContext();
const resolvedVariant = $derived(group.variant || variant);
const resolvedSize = $derived(group.size || size);
</script>
<Primitive
data-slot="toggle-group-item"
data-variant={resolvedVariant}
data-size={resolvedSize}
data-spacing={group.spacing}
{...props}
class={cn('group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg shrink-0 focus:z-10 focus-visible:z-10 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t', toggleVariants({ variant: resolvedVariant, size: resolvedSize }), classProp)}
/>import { getContext, setContext } from 'svelte';
import type { ToggleVariants } from '../toggle/index.js';
export type ToggleGroupContextValue = {
readonly variant: ToggleVariants['variant'];
readonly size: ToggleVariants['size'];
readonly spacing: number;
readonly orientation: 'horizontal' | 'vertical';
};
const key = Symbol('toggle-group');
const outsideGroup: ToggleGroupContextValue = { variant: undefined, size: undefined, spacing: 2, orientation: 'horizontal' };
export const getToggleGroupContext = (): ToggleGroupContextValue => getContext(key) ?? outsideGroup;
export const setToggleGroupContext = (value: ToggleGroupContextValue) => setContext(key, value);import type { ToggleGroupProps as BaseToggleGroupProps } from '@sveltery/base/toggle-group';
import type { ToggleProps } from '../toggle/index.js';
import type { ToggleVariants } from '../toggle/index.js';
export type ToggleGroupProps = BaseToggleGroupProps & ToggleVariants & { spacing?: number };
export type ToggleGroupItemProps = ToggleProps;
export type { ToggleGroupState } from '@sveltery/base/toggle-group';export { default as ToggleGroup } from './ToggleGroup.svelte';
export { default as ToggleGroupItem } from './ToggleGroupItem.svelte';
export type { ToggleGroupProps, ToggleGroupItemProps, ToggleGroupState } from './types.js';Update the import paths
Change the imports to match your project setup.
Usage
<script lang="ts">
import { ToggleGroup, ToggleGroupItem } from '$lib/components/ui/toggle-group';
</script><ToggleGroup multiple>
<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>Value
value is the array of pressed item values. Bind it to read and write the selection. Without multiple, pressing an item releases the others.
<script lang="ts">
let weight = $state(['normal']);
</script>
<ToggleGroup bind:value={weight} variant="outline">
<ToggleGroupItem value="light">Light</ToggleGroupItem>
<ToggleGroupItem value="normal">Normal</ToggleGroupItem>
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
</ToggleGroup>Variant and size
variant and size on the group apply to every item. Without them, each item uses its own.
<ToggleGroup variant="outline" size="sm" value={['all']}>
<ToggleGroupItem value="all">All</ToggleGroupItem>
<ToggleGroupItem value="missed">Missed</ToggleGroupItem>
</ToggleGroup>Spacing
spacing is the gap between items in spacing units. The default is 2. With spacing={0}, outline items join into one bar.
<ToggleGroup variant="outline" spacing={0}>
<ToggleGroupItem value="top">Top</ToggleGroupItem>
<ToggleGroupItem value="bottom">Bottom</ToggleGroupItem>
</ToggleGroup>Vertical
Arrow keys follow the orientation.
<ToggleGroup orientation="vertical" multiple spacing={1}>
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
</ToggleGroup>API reference
ToggleGroup and ToggleGroupItem are styled on top of the Sveltery Base ToggleGroup and Toggle primitives, which own the pressed state, roving focus and accessibility. See the Base UI Toggle Group documentation for the behavior they port.