Toggle Group

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

import { ThumbsDown, ThumbsUp } from "lucide-react";
import ToggleGroup from "@tailus-ui/ToggleGroup";

export const Overview = () => (
    <ToggleGroup.Root variant="mixed" type="single" aria-label="User feedback">
        <ToggleGroup.Item value="like">
            <ToggleGroup.Icon>
                <ThumbsUp />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="dislike">
            <ToggleGroup.Icon>
                <ThumbsDown />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
  </ToggleGroup.Root>
)

Installation

Install the primitive and Copy-Paste the component code in a .tsx file.

npm install @radix-ui/react-toggle-group
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import React, { createContext, useContext } from "react";
import { cloneElement } from "@lib/utils";
import { toggle, type ToggleRootProps } from "@tailus/themer";

const {group, root: item, icon } = toggle();

const RootContext = createContext<ToggleRootProps>({
  variant: "soft",
  intent: "primary",
  size: "md"
});

const ToggleGroupRoot = React.forwardRef<
  React.ElementRef<typeof ToggleGroupPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> & ToggleRootProps
>((
  {
    className,
    variant="soft",
    intent="primary",
    size="md",
    ...props
  }, forwardedRef
) => {
  
  return (
    <RootContext.Provider value={{variant, intent, size}}>
      <ToggleGroupPrimitive.Root className={group({size, className})} ref={forwardedRef} {...props} />
    </RootContext.Provider>
  );
});

// Creating the ToggleGroupItem component with forwardRef to pass the ref
const ToggleGroupItem = React.forwardRef<
  React.ElementRef<typeof ToggleGroupPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> & ToggleRootProps
>((
  {
    className,
    variant,
    intent,
    size,
    withLabel,
    ...props
  }, forwardedRef
) => {

  const {
    variant: rootVariant,
    intent: rootIntent,
    size: rootSize
  } = useContext(RootContext);

  variant = variant || rootVariant;
  intent = intent || rootIntent;
  size = size || rootSize;

  return (
    <ToggleGroupPrimitive.Item
      className={item({variant, intent, size, withLabel, className})} ref={forwardedRef} {...props}
    />
  );
});

interface ToggleIconProps {
  className?: string,
  children: React.ReactNode,
  size? : ToggleRootProps["size"]
}

const ToggleGroupIcon = ({className, children, size}: ToggleIconProps) => {
  const { size : rootSize } = useContext(RootContext);
  size = size || rootSize;
  return cloneElement(children as React.ReactElement, icon({size, className}));
};

export default {
  Root: ToggleGroupRoot,
  Item: ToggleGroupItem,
  Icon: ToggleGroupIcon,
}

export {
  ToggleGroupRoot,
  ToggleGroupItem,
  ToggleGroupIcon,
};

Usage

Import all the parts and build your Toggle Group.

import { ThumbsDown, ThumbsUp } from "lucide-react";
import ToggleGroup from "@tailus-ui/ToggleGroup";

export const Overview = () => (
    <ToggleGroup.Root variant="mixed" type="single" aria-label="User feedback">
        <ToggleGroup.Item value="like">
            <ToggleGroup.Icon>
                <ThumbsUp />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="dislike">
            <ToggleGroup.Icon>
                <ThumbsDown />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
  </ToggleGroup.Root>
)

Reference

Root

The parent component of the ToggleGroup component

Prop
Type
Default
variant
enum
soft
intent
enum
primary
size
enum
md

Item

The item of the ToggleGroup component

Prop
Type
Default
withLabel
boolean
false
variant
enum
soft
intent
enum
primary
size
enum
md

Icon

The Icon of the Toggle Item

Prop
Type
Default
size
enum
md

Examples

User Feedback

import { Angry, Frown, Meh, Smile } from "lucide-react";
import ToggleGroup from "@tailus-ui/ToggleGroup";

export const Feedback = () => (
    <ToggleGroup.Root size="sm" variant="mixed" intent="gray" type="single" data-shade="900" aria-label="user feedback">
        <ToggleGroup.Item value="smile">
            <ToggleGroup.Icon size="xs">
                <Smile />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="meh">
            <ToggleGroup.Icon size="xs">
                <Meh />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="frown">
            <ToggleGroup.Icon size="xs">
                <Frown />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="annoyed">
            <ToggleGroup.Icon size="sm">
                <Annoyed />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="angry">
            <ToggleGroup.Icon size="xs">
                <Angry />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
  </ToggleGroup.Root>
)

Text Formatting

import { Bold, Italic, Strikethrough, Underline } from "lucide-react";
import ToggleGroup from "@tailus-ui/ToggleGroup";

export const Formating = () => (
    <ToggleGroup.Root size="sm" type="multiple" aria-label="Text formatting">
        <ToggleGroup.Item value="bold">
            <ToggleGroup.Icon size="xs">
                <Bold />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="italic">
            <ToggleGroup.Icon size="xs">
                <Italic />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="underline">
            <ToggleGroup.Icon size="xs">
                <Underline />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="strikethrough">
            <ToggleGroup.Icon size="xs">
                <Strikethrough />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
  </ToggleGroup.Root>
)

Text Alignment

import { AlignCenter, AlignJustify, AlignLeft, AlignRight } from "lucide-react";
import ToggleGroup from "@tailus-ui/ToggleGroup";

export const Alignment = () => (
    <ToggleGroup.Root size="sm" type="single" aria-label="Text alignment">
        <ToggleGroup.Item value="left">
            <ToggleGroup.Icon size="xs">
                <AlignLeft />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="center">
            <ToggleGroup.Icon size="xs">
                <AlignCenter />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="right">
            <ToggleGroup.Icon size="xs">
                <AlignRight />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
        <ToggleGroup.Item value="justify">
            <ToggleGroup.Icon size="xs">
                <AlignJustify />
            </ToggleGroup.Icon>
        </ToggleGroup.Item>
  </ToggleGroup.Root>
)