Toggle Group
A group of toggle buttons. The group
binding gives you the familiar Svelte feel.
<script lang="ts">
import * as ToggleGroup from "$lib/components/toggle-group/index.js";
let group: string[] = $state([]);
</script>
<p>Select your chocolate toppings</p>
<ToggleGroup.Root bind:group variant="default" focus={{ loop: true, roving: true }}>
<ToggleGroup.Item value="nuts">Nuts</ToggleGroup.Item>
<ToggleGroup.Item value="caramel" variant="outline">Caramel</ToggleGroup.Item>
<ToggleGroup.Item value="salt" active>Sea Salt</ToggleGroup.Item>
<ToggleGroup.Item value="crunch" active>Crunch</ToggleGroup.Item>
</ToggleGroup.Root>
<p>Choice: {group}</p>
Select your chocolate toppings
Choice: salt,crunch
Headless component
The headless component is built in a few lines of code by applying the Group
mixin to
the ToggleButton
. So all the heavy-lifting is done by the Group
mixin, like
tracking the active items and managing focus
import { Group } from "chocobytes/blocks/group.svelte.js";
import type { Required } from "chocobytes/utils/types.js";
import { ToggleButton, type ToggleOptions } from "chocobytes/headless/toggle.svelte.js";
export class ToggleGroup extends Group(ToggleButton) {
createItem = (options: Required<ToggleOptions, "value">) => {
return new this.Item(options);
};
}
You have access to all the Group
focus options like loop
, exclusive
etc. and the group
property is bindable as demonstrated in the following demo. Use the
keyboard arrows to play with the loop:
<script lang="ts">
import { choco } from "chocobytes";
import { ToggleGroup } from "chocobytes/headless/toggle-group.svelte.js";
let group = $state(["nuts"]);
const toppings = new ToggleGroup({
loop: true,
// bind the group
group: () => group,
setGroup(v) {
group = v;
},
});
toppings.createItem({ value: "nuts", active: true });
toppings.createItem({ value: "caramel" });
toppings.createItem({ value: "crunch" });
</script>
<div class="flex justify-center gap-2">
{#each toppings.items as item}
<button class="rounded py-2 px-4 outline aria-pressed:underline" use:choco={item}
>{item.value}</button
>
{/each}
</div>
<!-- This part is only to demonstrate the bindability -->
<div class="mt-8 flex gap-2">
{#each ["nuts", "caramel", "crunch"] as value}
<label>
<input type="checkbox" {value} bind:group />
{value}
</label>
{/each}
</div>
<p>Choice: {toppings.group}</p>
Choice: nuts