🚧 Under development — suggestions for new items are always welcome! ✨

Switch

A control that allows the user to toggle between checked and not checked.

Bundle Size Impact

this1.22 KB
shadcn11.42 KB(+834%)
baseui12.56 KB(+927%)
headlessui13.79 KB(+1027%)
chakraui29.07 KB(+2276%)
heroui29.46 KB(+2307%)
material36.6 KB(+2891%)
antd38.09 KB(+3013%)

Install

pnpm dlx shadcn@latest add https://p.livog.com/r/switch.json

Code

import { useId, type CSSProperties, type ComponentPropsWithoutRef, type ReactNode } from 'react'
import clsx from 'clsx'

export type SwitchProps = Omit<ComponentPropsWithoutRef<'input'>, 'size'> & {
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
  enabledIcon?: ReactNode
  disabledIcon?: ReactNode
}

export function Switch({
  size = 'sm',
  disabled = false,
  id,
  className,
  style: styleProp,
  checked,
  defaultChecked,
  enabledIcon,
  disabledIcon,
  ...props
}: SwitchProps) {
  const autoId = useId()
  const generatedId = id ?? autoId
  const style: CSSProperties & { [key: `--${string}`]: string | number } = { ...(styleProp ?? {}) }

  const sizeValues = {
    xs: '1rem',
    sm: '1.25rem',
    md: '1.5rem',
    lg: '1.875rem',
    xl: '2rem'
  }

  const sizeValue = sizeValues[size] ?? sizeValues.md
  if (size !== 'md') style['--size'] = sizeValue

  const controlProps = checked !== undefined ? { checked } : { defaultChecked }

  if (enabledIcon || disabledIcon) {
    return (
      <label htmlFor={generatedId} className={clsx('switch', className)} style={style}>
        <input
          type="checkbox"
          id={generatedId}
          disabled={disabled}
          {...props}
          {...controlProps}
        />
        {disabledIcon}
        {enabledIcon}
      </label>
    )
  }

  return (
    <input
      type="checkbox"
      id={generatedId}
      className={clsx('switch peer', className)}
      disabled={disabled}
      style={style}
      {...props}
      {...controlProps}
    />
  )
}

export default Switch