Toggle Group

A group of toggle buttons that allows single or multiple selection from a set of options, commonly used for formatting toolbars like text alignment.

import { ToggleGroup, ToggleGroupItem } from "~/components/toggle-group";

export default function ToggleGroupBasicDemo() {
  return (
    <ToggleGroup defaultValue={["left"]}>
      <ToggleGroupItem value="left" aria-label="Align Left">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="17" y1="10" x2="3" y2="10" />
          <line x1="21" y1="6" x2="3" y2="6" />
          <line x1="21" y1="14" x2="3" y2="14" />
          <line x1="17" y1="18" x2="3" y2="18" />
        </svg>
      </ToggleGroupItem>
      <ToggleGroupItem value="center" aria-label="Align Center">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="18" y1="10" x2="6" y2="10" />
          <line x1="21" y1="6" x2="3" y2="6" />
          <line x1="21" y1="14" x2="3" y2="14" />
          <line x1="18" y1="18" x2="6" y2="18" />
        </svg>
      </ToggleGroupItem>
      <ToggleGroupItem value="right" aria-label="Align Right">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="21" y1="10" x2="7" y2="10" />
          <line x1="21" y1="6" x2="3" y2="6" />
          <line x1="21" y1="14" x2="3" y2="14" />
          <line x1="21" y1="18" x2="7" y2="18" />
        </svg>
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Installation

CLI

Run the following command to add the component to your project:

npx @ark-preset/cli@latest add toggle-group

Manual

Create the recipe file at src/components/recipes/toggle-group.ts:

import { tv, type VariantProps } from "tailwind-variants";

export const toggleGroupVariants = tv({
  slots: {
    root: "inline-flex items-center gap-1 data-[orientation=vertical]:flex-col",
    item: "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium border border-input bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 transition duration-300 motion-safe:hover:-translate-y-0.5 motion-safe:active:translate-y-0.5 active:duration-150 data-[state=on]:bg-primary data-[state=on]:text-primary-foreground data-[state=on]:border-transparent data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
  },
  variants: {
    size: {
      sm: { item: "h-8 p-2" },
      md: { item: "h-9 p-2.5" },
      lg: { item: "h-10 p-3" },
    },
  },
  defaultVariants: {
    size: "sm",
  },
});

export type ToggleGroupVariants = VariantProps<typeof toggleGroupVariants>;

Create the component directory and files.

src/components/toggle-group/toggle-group.base.tsx:

import { ToggleGroup as ArkToggleGroup } from "@ark-ui/solid/toggle-group";
import { splitProps, type Component } from "solid-js";
import { toggleGroupVariants, type ToggleGroupVariants } from "../recipes/toggle-group";

const styles = toggleGroupVariants();

const Root: Component<ArkToggleGroup.RootProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkToggleGroup.Root class={styles.root({ class: local.class })} {...others} />;
};

const RootProvider: Component<ArkToggleGroup.RootProviderProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkToggleGroup.RootProvider class={styles.root({ class: local.class })} {...others} />;
};

const Item: Component<ArkToggleGroup.ItemProps & ToggleGroupVariants> = (props) => {
  const [local, others] = splitProps(props, ["class", "size"]);
  return (
    <ArkToggleGroup.Item
      class={styles.item({ class: local.class, size: local.size })}
      {...others}
    />
  );
};

export const ToggleGroup = { Root, RootProvider, Item };

src/components/toggle-group/index.tsx:

import { ToggleGroup as ToggleGroupBase } from "./toggle-group.base";

const ToggleGroup = ToggleGroupBase.Root;
const ToggleGroupItem = ToggleGroupBase.Item;
export { ToggleGroup, ToggleGroupItem, ToggleGroupBase };

export { toggleGroupVariants, type ToggleGroupVariants } from "../recipes/toggle-group";

Note: Make sure your project has the Tailwind CSS theme variables set up (--background, --foreground, --ring, --border, etc.) or override the utility classes to match your design system.

Usage

Basic Usage

import { ToggleGroup, ToggleGroupItem } from "~/components/toggle-group";

export default function ToggleGroupBasicDemo() {
  return (
    <ToggleGroup defaultValue={["left"]}>
      <ToggleGroupItem value="left" aria-label="Align Left">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="17" y1="10" x2="3" y2="10" />
          <line x1="21" y1="6" x2="3" y2="6" />
          <line x1="21" y1="14" x2="3" y2="14" />
          <line x1="17" y1="18" x2="3" y2="18" />
        </svg>
      </ToggleGroupItem>
      <ToggleGroupItem value="center" aria-label="Align Center">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="18" y1="10" x2="6" y2="10" />
          <line x1="21" y1="6" x2="3" y2="6" />
          <line x1="21" y1="14" x2="3" y2="14" />
          <line x1="18" y1="18" x2="6" y2="18" />
        </svg>
      </ToggleGroupItem>
      <ToggleGroupItem value="right" aria-label="Align Right">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="21" y1="10" x2="7" y2="10" />
          <line x1="21" y1="6" x2="3" y2="6" />
          <line x1="21" y1="14" x2="3" y2="14" />
          <line x1="21" y1="18" x2="7" y2="18" />
        </svg>
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Multiple Selection

Use the multiple prop to allow selecting multiple items.

import { ToggleGroup, ToggleGroupItem } from "~/components/toggle-group";

export default function ToggleGroupMultipleDemo() {
  return (
    <ToggleGroup defaultValue={["bold"]} multiple>
      <ToggleGroupItem value="bold" aria-label="Toggle bold">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" />
          <path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" />
        </svg>
      </ToggleGroupItem>
      <ToggleGroupItem value="italic" aria-label="Toggle italic">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <line x1="19" y1="4" x2="10" y2="4" />
          <line x1="14" y1="20" x2="5" y2="20" />
          <line x1="15" y1="4" x2="9" y2="20" />
        </svg>
      </ToggleGroupItem>
      <ToggleGroupItem value="underline" aria-label="Toggle underline">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="18"
          height="18"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3" />
          <line x1="4" y1="21" x2="20" y2="21" />
        </svg>
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Sizes

Use the size prop to change the toggle group item size.

import { ToggleGroup, ToggleGroupItem } from "~/components/toggle-group";

export default function ToggleGroupSizesDemo() {
  return (
    <div class="flex flex-col gap-6">
      <ToggleGroup defaultValue={["sm"]}>
        <ToggleGroupItem size="sm" value="sm">
          Sm
        </ToggleGroupItem>
        <ToggleGroupItem size="sm" value="md">
          Sm
        </ToggleGroupItem>
        <ToggleGroupItem size="sm" value="lg">
          Sm
        </ToggleGroupItem>
      </ToggleGroup>
      <ToggleGroup defaultValue={["md"]}>
        <ToggleGroupItem size="md" value="sm">
          Md
        </ToggleGroupItem>
        <ToggleGroupItem size="md" value="md">
          Md
        </ToggleGroupItem>
        <ToggleGroupItem size="md" value="lg">
          Md
        </ToggleGroupItem>
      </ToggleGroup>
      <ToggleGroup defaultValue={["lg"]}>
        <ToggleGroupItem size="lg" value="sm">
          Lg
        </ToggleGroupItem>
        <ToggleGroupItem size="lg" value="md">
          Lg
        </ToggleGroupItem>
        <ToggleGroupItem size="lg" value="lg">
          Lg
        </ToggleGroupItem>
      </ToggleGroup>
    </div>
  );
}

Advanced Usage

Root Provider

Use ToggleGroupBase.RootProvider when you need to control the toggle group state externally.

Selected: left

import { Index, createMemo } from "solid-js";
import { ToggleGroupBase, ToggleGroupItem } from "~/components/toggle-group";
import { useToggleGroup } from "@ark-ui/solid/toggle-group";

const alignments = [
  { value: "left", label: "Left" },
  { value: "center", label: "Center" },
  { value: "right", label: "Right" },
];

export default function ToggleGroupRootProviderDemo() {
  const toggleGroup = useToggleGroup({ defaultValue: ["left"] });
  const value = createMemo(() => toggleGroup().value);

  return (
    <div>
      <p class="text-sm text-muted-foreground">Selected: {value().join(", ")}</p>
      <ToggleGroupBase.RootProvider value={toggleGroup}>
        <Index each={alignments}>
          {(alignment) => (
            <ToggleGroupItem value={alignment().value}>{alignment().label}</ToggleGroupItem>
          )}
        </Index>
      </ToggleGroupBase.RootProvider>
    </div>
  );
}
import { useToggleGroup } from "@ark-ui/solid/toggle-group";
import { ToggleGroupBase, ToggleGroupItem } from "~/components/toggle-group";

const tg = useToggleGroup({ defaultValue: ["left"] });

<ToggleGroupBase.RootProvider value={tg}>
  <ToggleGroupItem value="left"><AlignLeftIcon /></ToggleGroupItem>
  <ToggleGroupItem value="center"><AlignCenterIcon /></ToggleGroupItem>
  <ToggleGroupItem value="right"><AlignRightIcon /></ToggleGroupItem>
</ToggleGroupBase.RootProvider>

API Reference

See the Ark UI Toggle Group documentation.