Toggle

A two-state button that can be either on or off.

import { Bold } from "lucide-react";
import Toggle from "@tailus-ui/Toggle";

export const Overview = () => (
    <Toggle.Root aria-label="Toggle bold">
        <Toggle.Icon>
            <Bold />
        </Toggle.Icon>
  </Toggle.Root>
)

Installation

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

npm install @radix-ui/react-toggle
import {Root} from "@radix-ui/react-toggle";
import React from "react";
import { cloneElement } from "@lib/utils";
import { toggle, type ToggleRootProps, type ToggleIconProps as ToggleIconVariants } from "@tailus/themer";

const {root, icon} = toggle();

const ToggleRoot = React.forwardRef<
  React.ElementRef<typeof Root>,
  React.ComponentPropsWithoutRef<typeof Root> & ToggleRootProps
>(({
     className,
     variant = "soft",
     size = "md",
      intent = "primary",
     withLabel = false,
     ...props
   },
   forwardedRef
) => {
  return (
      <Root
        className={root({variant, size, withLabel, intent, className})}
        ref={forwardedRef}
        {...props}
      />
  )
});

interface ToggleIconProps extends ToggleIconVariants {
  className?: string,
  children: React.ReactNode
}

const ToggleIcon = ({className, size, children}: ToggleIconProps) => {
  return cloneElement(children as React.ReactElement, icon({size, className}));
};

export default {
  Root: ToggleRoot,
  Icon: ToggleIcon,
}

export {
  ToggleRoot,
  ToggleIcon,
};

Usage

Import all the parts and build your Toggle.

import { Bold } from "lucide-react";
import Toggle from "@tailus-ui/Toggle";

export const Overview = () => (
    <Toggle.Root aria-label="Toggle bold">
        <Toggle.Icon>
            <Bold />
        </Toggle.Icon>
  </Toggle.Root>
)

Reference

Root

The parent component of the Toggle component

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

Icon

The Icon of the Toggle component

Prop
Type
Default
size
enum
md

Examples

With Label

import { Bold } from "lucide-react";
import Toggle from "@tailus-ui/Toggle";

export const Overview = () => (
    <Toggle.Root withLabel aria-label="Toggle bold">
        <Toggle.Icon>
            <Bold />
        </Toggle.Icon>
        <span>Bold</span>
  </Toggle.Root>
)

Plain

import { Bold } from "lucide-react";
import Toggle from "@tailus-ui/Toggle";

export const Overview = () => (
    <Toggle.Root variant="mixed" aria-label="Toggle bold">
        <Toggle.Icon>
            <Bold />
        </Toggle.Icon>
  </Toggle.Root>
)

Mixed

import { Bold } from "lucide-react";
import Toggle from "@tailus-ui/Toggle";

export const Overview = () => (
    <Toggle.Root variant="mixed" aria-label="Toggle bold">
        <Toggle.Icon>
            <Bold />
        </Toggle.Icon>
  </Toggle.Root>
)

Soft To Solid

import { Bold } from "lucide-react";
import Toggle from "@tailus-ui/Toggle";

export const Overview = () => (
    <Toggle.Root variant="softToSolid" aria-label="Toggle bold">
        <Toggle.Icon>
            <Bold />
        </Toggle.Icon>
  </Toggle.Root>
)

Colors

primary

secondary

accent

gray

neutral

plain

soft

softToSolid

mixed

import { Caption } from "@tailus-ui/typography";
import { type ToggleRootProps } from "@tailus/themer";
import Toggle from "@tailus-ui/Toggle";
import { Bold } from "lucide-react";

const colors:ToggleRootProps["intent"][] = ["primary", "secondary", "accent", "gray", "neutral"]

type Variant = {
    variant: ToggleRootProps["variant"],
    colors : ToggleRootProps["intent"][]
}

const variants:Variant[] = [
    {
        variant: "plain",
        colors,
    },
    {
        variant: "soft",
        colors,
    },
    {
        variant: "softToSolid",
        colors,
    },
    {
        variant: "mixed",
        colors,
    }
]

export const Colors = () => (
    <div className="grid items-end [grid-template-columns:1fr_auto] gap-4">
        <div className="py-4 space-y-4">
            {
                colors.map((color, index) => (
                    <div key={index} className="h-8 flex items-center">
                        <Caption className="capitalize">{color}</Caption>
                    </div>
                ))
            }
        </div>
        <div className="overflow-x-auto sm:overflow-visible">
            <div className="w-max space-y-4">
                <div className="px-4 grid gap-4 grid-cols-4">
                    {
                        variants.map((variant, index) => (
                            <Caption key={index} className="capitalize last:pl-3.5">{variant.variant}</Caption>
                        ))
                    }
                </div>
                <div className="border p-4 grid grid-cols-4 gap-4 rounded-[--card-radius]">
                
                {
                    variants.map((variant, index) => (
                        <div key={index} className="space-y-4">
                            {
                                variant.colors.map((color, index) => (
                                    <Toggle.Root variant={variant.variant} intent={color} aria-label="Toggle bold">
                                        <Toggle.Icon>
                                            <Bold />
                                        </Toggle.Icon>
                                    </Toggle.Root>
                                ))
                            }
                        </div>
                    ))
                }
                </div>
            </div>
        </div>
    </div>
)

Sizes

plain

soft

softToSolid

mixed

xs

sm

md

lg

xl

import { Caption } from "@tailus-ui/typography";
import { type ToggleRootProps } from "@tailus/themer";
import Toggle from "@tailus-ui/Toggle";
import { Bold } from "lucide-react";

const colors:ToggleRootProps["intent"][] = ["primary", "secondary", "accent", "gray", "neutral"]

type Variant = {
    variant: ToggleRootProps["variant"],
    colors : ToggleRootProps["intent"][]
}

const variants:Variant[] = [
    {
        variant: "plain",
        colors,
    },
    {
        variant: "soft",
        colors,
    },
    {
        variant: "softToSolid",
        colors,
    },
    {
        variant: "mixed",
        colors,
    }
]

export const Colors = () => (
    <div className="grid items-end [grid-template-columns:1fr_auto] gap-4">
        <div className="py-4 space-y-4">
            {
                colors.map((color, index) => (
                    <div key={index} className="h-8 flex items-center">
                        <Caption className="capitalize">{color}</Caption>
                    </div>
                ))
            }
        </div>
        <div className="overflow-x-auto sm:overflow-visible">
            <div className="w-max space-y-4">
                <div className="px-4 grid gap-4 grid-cols-4">
                    {
                        variants.map((variant, index) => (
                            <Caption key={index} className="capitalize last:pl-3.5">{variant.variant}</Caption>
                        ))
                    }
                </div>
                <div className="border p-4 grid grid-cols-4 gap-4 rounded-[--card-radius]">
                
                {
                    variants.map((variant, index) => (
                        <div key={index} className="space-y-4">
                            {
                                variant.colors.map((color, index) => (
                                    <Toggle.Root variant={variant.variant} intent={color} aria-label="Toggle bold">
                                        <Toggle.Icon>
                                            <Bold />
                                        </Toggle.Icon>
                                    </Toggle.Root>
                                ))
                            }
                        </div>
                    ))
                }
                </div>
            </div>
        </div>
    </div>
)