Skip to content
Components

Toggle Group

Groups related toggle buttons into a single selection control.

Playground

size

Sets item height and horizontal padding.

scheme

Applies a semantic color to selected items.

disabled

Prevents every item from being toggled.

Usage

tsx
import { ToggleGroup, ToggleGroupItem } from "earthling-ui/toggle-group";

export function Example() {
  return (
    <>
      <ToggleGroup type="single" defaultValue="list" aria-label="View">
        <ToggleGroupItem value="list">List</ToggleGroupItem>
        <ToggleGroupItem value="grid">Grid</ToggleGroupItem>
      </ToggleGroup>
    </>
  );
}
  • Choose type single for one selection or multiple for independent selections.
  • Give the group and icon-only items accessible labels.
  • Keep choices short and mutually understandable at a glance.

Installation

Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.

bash
npm install earthling-ui

Use the component import shown above. Package updates keep the implementation current.

API reference

Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.

tsx
// Generated by dts-bundle-generator v9.5.1

import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
import { VariantProps } from 'class-variance-authority';
import { ComponentPropsWithoutRef } from 'react';

export declare const ToggleGroup: import("react").ForwardRefExoticComponent<(ComponentPropsWithoutRef<import("react").ForwardRefExoticComponent<(ToggleGroupPrimitive.ToggleGroupSingleProps | ToggleGroupPrimitive.ToggleGroupMultipleProps) & import("react").RefAttributes<HTMLDivElement>>> & VariantProps<(props?: ({
	material?: "paper" | null | undefined;
	scheme?: "default" | "primary" | "secondary" | "tertiary" | "neutral" | "muted" | "good" | "caution" | "bad" | null | undefined;
	size?: "sm" | "md" | "lg" | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string>) & import("react").RefAttributes<HTMLDivElement>>;
export declare const ToggleGroupItem: import("react").ForwardRefExoticComponent<Omit<ToggleGroupPrimitive.ToggleGroupItemProps & import("react").RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
	material?: "paper" | null | undefined;
	scheme?: "default" | "primary" | "secondary" | "tertiary" | "neutral" | "muted" | "good" | "caution" | "bad" | null | undefined;
	size?: "sm" | "md" | "lg" | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string> & import("react").RefAttributes<HTMLButtonElement>>;

export {};

Runtime dependencies: @radix-ui/react-toggle-group, class-variance-authority, cnfast.

Source

Use the eject command to copy this implementation with its required helpers and project-specific imports.

View Toggle Group implementation
tsx
"use client";

import {
  createContext,
  forwardRef,
  useContext,
  type ComponentPropsWithoutRef,
  type ComponentRef,
} from "react";
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/utils/cn";
import { schemes } from "@/utils/variants";

const toggleGroupVariants = cva("flex items-center justify-center", {
  variants: {
    material: {
      paper: "rounded-(--radius-control) bg-muted text-muted-foreground",
    },
    scheme: schemes,
    size: { sm: "p-1", md: "p-1", lg: "p-1" },
  },
  defaultVariants: { material: "paper", size: "md", scheme: "primary" },
});

const ToggleGroupContext = createContext<
  VariantProps<typeof toggleGroupVariants>
>({ size: "md", material: "paper", scheme: "primary" });

const ToggleGroup = forwardRef<
  ComponentRef<typeof ToggleGroupPrimitive.Root>,
  ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
    VariantProps<typeof toggleGroupVariants>
>(
  (
    {
      className,
      material = "paper",
      size = "md",
      scheme = "primary",
      children,
      ...props
    },
    ref,
  ) => (
    <ToggleGroupPrimitive.Root
      ref={ref}
      className={cn(toggleGroupVariants({ material, size, scheme }), className)}
      {...props}
    >
      <ToggleGroupContext.Provider value={{ material, scheme, size }}>
        {children}
      </ToggleGroupContext.Provider>
    </ToggleGroupPrimitive.Root>
  ),
);

ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;

const toggleGroupItemVariants = cva(
  "inline-flex cursor-pointer items-center justify-center gap-1.5 text-sm font-medium ring-offset-background hover:bg-(--scheme-tint)/5 focus-visible:relative focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-outline focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
  {
    variants: {
      material: {
        paper:
          "data-[state=on]:bg-(--scheme-tint) data-[state=on]:text-(--scheme-foreground) data-[state=on]:shadow-xs rounded-[max(0px,calc(var(--radius-control)-0.25rem))]",
      },
      scheme: schemes,
      size: {
        sm: "h-7 px-2.5 min-w-9",
        md: "h-8 px-3 min-w-10",
        lg: "h-9 px-5 min-w-11",
      },
    },
    defaultVariants: { material: "paper", size: "md" },
  },
);

const ToggleGroupItem = forwardRef<
  ComponentRef<typeof ToggleGroupPrimitive.Item>,
  ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
    VariantProps<typeof toggleGroupVariants>
>(({ className, children, material, scheme, size, ...props }, ref) => {
  const context = useContext(ToggleGroupContext);

  return (
    <ToggleGroupPrimitive.Item
      ref={ref}
      className={cn(
        toggleGroupItemVariants({
          material: material ?? context.material,
          scheme: scheme ?? context.scheme,
          size: size ?? context.size,
        }),
        className,
      )}
      {...props}
    >
      {children}
    </ToggleGroupPrimitive.Item>
  );
});

ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;

export { ToggleGroup, ToggleGroupItem };