dotUI
dotUI
beta
  1. Components
  2. Inputs
  3. Switch

Switch

Switches allow users to turn an individual option on or off.

<Switch>Focus mode</Switch>

Installation

Install the following dependencies:

npm install react-aria-components

Copy and paste the following code into your project.

"use client";

import * as React from "react";
import {
  Switch as AriaSwitch,
  composeRenderProps,
  type SwitchProps as AriaSwitchProps,
} from "react-aria-components";
import { tv, type VariantProps } from "tailwind-variants";
import { focusRing } from "@/lib/utils/styles";

const switchStyles = tv({
  slots: {
    root: "group/switch flex items-center gap-3 disabled:text-fg-disabled",
    wrapper: [
      focusRing(),
      "inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
      "group-disabled/switch:cursor-not-allowed group-disabled/switch:bg-transparent group-disabled/switch:border group-disabled/switch:border-border-disabled group-disabled/switch:group-selected/switch:border-none group-disabled/switch:group-selected/switch:bg-bg-disabled group-selected/switch:bg-border-focus bg-bg-neutral",
    ],
    indicator:
      "pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-all duration-200 origin-right group-disabled/switch:bg-fg-disabled",
    label: "",
  },
  variants: {
    size: {
      sm: {
        wrapper: "h-5 w-9",
        indicator:
          "size-4 group-pressed/switch:w-5 group-selected/switch:ml-4 group-selected/switch:group-pressed/switch:ml-3",
      },
      md: {
        wrapper: "h-6 w-11",
        indicator:
          "size-5 group-pressed/switch:w-6 group-selected/switch:ml-5 group-selected/switch:group-pressed/switch:ml-4",
      },
      lg: {
        wrapper: "h-7 w-12",
        indicator:
          "size-6 group-pressed/switch:w-7 group-selected/switch:ml-6 group-selected/switch:group-pressed/switch:ml-5",
      },
    },
  },
  defaultVariants: {
    size: "md",
  },
});

interface SwitchProps
  extends Omit<AriaSwitchProps, "className">,
    VariantProps<typeof switchStyles> {
  className?: string;
}
const Switch = ({ className, size, ...props }: SwitchProps) => {
  const { root, wrapper, indicator, label } = switchStyles({ size });

  return (
    <AriaSwitch className={root({ className })} {...props}>
      {composeRenderProps(props.children, (children) => (
        <>
          <span className={wrapper({ className })}>
            <span className={indicator({})} style={{ contain: "layout" }} />
          </span>
          {children && <span className={label({})}>{children}</span>}
        </>
      ))}
    </AriaSwitch>
  );
};

export { Switch };

Update the import paths to match your project setup.

Usage

Use switch for communicating activation (e.g. on/off states), while checkboxes are best used for communicating selection (e.g. multiple table rows). Switches, unlike checkboxes, can't have an error state.

Options

Size

Use the size prop to control the size of the switch. The default variant is "md".

<Switch size="sm" />
<Switch size="md" />
<Switch size="lg" />

Label

A visual label can be provided using the component children or a hidden label using aria-label prop.

<Switch>Focus mode</Switch>
<Switch aria-label="Focus mode" />

Disabled

Use the isDisabled prop to disable the switch.

<Switch isDisabled>Focus Mode</Switch>

Uncontrolled

The defaultValue prop can be used to set the default state.

<Switch defaultSelected>Airplane Mode</Switch>

Controlled

Use the isSelected and onChange props to control the value of the input.

const [isSelected, setSelected] = React.useState(true);
return (
  <Switch isSelected={isSelected} onChange={setSelected}>
    Airplane Mode
  </Switch>
)

API Reference

PropTypeDefaultDescription
size
"sm" | "md" | "lg"
"md"
The size of the switch.
inputRef
MutableRefObject<HTMLInputElement>
-
A ref for the HTML input element.
defaultSelected
boolean
-
Whether the element should be selected (uncontrolled).
isSelected
boolean
-
Whether the element should be selected (controlled).
value
string
-
The value of the input element, used when submitting an HTML form.
isDisabled
boolean
-
Whether the input is disabled.
isReadOnly
boolean
-
Whether the input can be selected but not changed by the user.
autoFocus
boolean
-
Whether the element should receive focus on render.
name
string
-
The name of the input element, used when submitting an HTML
children
ReactNode | (values: CheckboxRenderProps & {defaultChildren: ReactNode | undefined}) => ReactNode
-
The children of the component. A function may be provided to alter the children based on component state.
EventTypeDescription
onChange
(isSelected: boolean) => void
Handler that is called when the Switch's selection state changes.
onFocus
(e: FocusEvent<Target>) => void
Handler that is called when the Switch receives focus.
onBlur
(e: FocusEvent<Target>) => void
Handler that is called when the Switch loses focus.
onFocusChange
(isFocused: boolean) => void
Handler that is called when the Switch's focus status changes.
onKeyDown
(e: KeyboardEvent) => void
Handler that is called when a key is pressed.
onKeyUp
(e: KeyboardEvent) => void
Handler that is called when a key is released.
onHoverStart
(e: HoverEvent) => void
Handler that is called when a hover interaction starts.
onHoverEnd
(e: HoverEvent) => void
Handler that is called when a hover interaction ends.
onHoverChange
(isHovering: boolean) => void
Handler that is called when the hover state changes.
Data attributeDescription
[data-selected]
Whether the switch is selected.
[data-hovered]
Whether the switch is currently hovered with a mouse.
[data-pressed]
Whether the switch is currently in a pressed state.
[data-focused]
Whether the switch is focused, either via a mouse or keyboard.
[data-focus-visible]
Whether the switch is keyboard focused.
[data-disabled]
Whether the switch is disabled.
[data-readonly]
Whether the switch is read only.

Accessibility

Keyboard interactions

KeyDescription
Space Enter
Toggles the component's state.

Built by mehdibha. The source code is available on GitHub.