Switch
A toggle switch component for boolean states
Import
import { Switch, SwitchGroup } from '@heroui/react';Usage
"use client";
import {Label, Switch} from "@heroui/react";
export function Basic() {
  return (
    <Switch>
      <Switch.Control>
        <Switch.Thumb />
      </Switch.Control>
      <Label className="text-sm">Enable notifications</Label>
    </Switch>
  );
}Anatomy
Import all parts and piece them together.
import {Switch} from '@heroui/react';
export default () => (
  <Switch>
    <Switch.Control>
      <Switch.Thumb>
        <Switch.Icon />  {/* Optional */}
      </Switch.Thumb>
    </Switch.Control>
  </Switch>
);Disabled
"use client";
import {Label, Switch} from "@heroui/react";
export function Disabled() {
  return (
    <Switch isDisabled>
      <Switch.Control>
        <Switch.Thumb />
      </Switch.Control>
      <Label className="text-sm">Enable notifications</Label>
    </Switch>
  );
}Default Selected
"use client";
import {Label, Switch} from "@heroui/react";
export function DefaultSelected() {
  return (
    <Switch defaultSelected>
      <Switch.Control>
        <Switch.Thumb />
      </Switch.Control>
      <Label className="text-sm">Enable notifications</Label>
    </Switch>
  );
}Controlled
Switch is off
"use client";
import {Label, Switch} from "@heroui/react";
import React from "react";
export function Controlled() {
  const [isSelected, setIsSelected] = React.useState(false);
  return (
    <div className="flex flex-col gap-4">
      <Switch isSelected={isSelected} onChange={setIsSelected}>
        <Switch.Control>
          <Switch.Thumb />
        </Switch.Control>
        <Label className="text-sm">Enable notifications</Label>
      </Switch>
      <p className="text-muted text-sm">Switch is {isSelected ? "on" : "off"}</p>
    </div>
  );
}Without Label
"use client";
import {Switch} from "@heroui/react";
export function WithoutLabel() {
  return (
    <Switch aria-label="Enable notifications">
      <Switch.Control>
        <Switch.Thumb />
      </Switch.Control>
    </Switch>
  );
}Sizes
"use client";
import {Label, Switch} from "@heroui/react";
export function Sizes() {
  return (
    <div className="flex gap-6">
      <Switch size="sm">
        <Switch.Control>
          <Switch.Thumb />
        </Switch.Control>
        <Label className="text-xs">Small</Label>
      </Switch>
      <Switch size="md">
        <Switch.Control>
          <Switch.Thumb />
        </Switch.Control>
        <Label className="text-sm">Medium</Label>
      </Switch>
      <Switch size="lg">
        <Switch.Control>
          <Switch.Thumb />
        </Switch.Control>
        <Label className="text-base">Large</Label>
      </Switch>
    </div>
  );
}Label Position
"use client";
import {Label, Switch} from "@heroui/react";
export function LabelPosition() {
  return (
    <div className="flex flex-col gap-4">
      <Switch>
        <Switch.Control>
          <Switch.Thumb />
        </Switch.Control>
        <Label className="text-sm">Label after</Label>
      </Switch>
      <Switch>
        <Label className="text-sm">Label before</Label>
        <Switch.Control>
          <Switch.Thumb />
        </Switch.Control>
      </Switch>
    </div>
  );
}With Icons
"use client";
import {Switch} from "@heroui/react";
import {Icon} from "@iconify/react";
export function WithIcons() {
  const icons = {
    check: {
      off: "gravity-ui:power",
      on: "gravity-ui:check",
      selectedControlClass: "bg-green-500/80",
    },
    darkMode: {
      off: "gravity-ui:moon",
      on: "gravity-ui:sun",
      selectedControlClass: "",
    },
    microphone: {
      off: "gravity-ui:microphone",
      on: "gravity-ui:microphone-slash",
      selectedControlClass: "bg-red-500/80",
    },
    notification: {
      off: "gravity-ui:bell-slash",
      on: "gravity-ui:bell-fill",
      selectedControlClass: "bg-purple-500/80",
    },
    volume: {
      off: "gravity-ui:volume-fill",
      on: "gravity-ui:volume-slash-fill",
      selectedControlClass: "bg-blue-500/80",
    },
  };
  return (
    <div className="flex gap-3">
      {Object.entries(icons).map(([key, value]) => (
        <Switch key={key} defaultSelected size="lg">
          {({isSelected}) => (
            <>
              <Switch.Control className={isSelected ? value.selectedControlClass : ""}>
                <Switch.Thumb>
                  <Switch.Icon>
                    <Icon
                      className={`${isSelected ? "opacity-100" : "opacity-70"} size-3 text-inherit`}
                      icon={isSelected ? value.on : value.off}
                    />
                  </Switch.Icon>
                </Switch.Thumb>
              </Switch.Control>
            </>
          )}
        </Switch>
      ))}
    </div>
  );
}With Description
"use client";
import {Description, Label, Switch} from "@heroui/react";
export function WithDescription() {
  return (
    <div className="max-w-sm">
      <Switch>
        <div className="flex gap-3">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <div className="flex flex-col gap-1">
            <Label className="text-sm">Public profile</Label>
            <Description>Allow others to see your profile information</Description>
          </div>
        </div>
      </Switch>
    </div>
  );
}Group
"use client";
import {Label, Switch, SwitchGroup} from "@heroui/react";
export function Group() {
  return (
    <SwitchGroup>
      <SwitchGroup.Items>
        <Switch name="notifications">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">Allow Notifications</Label>
        </Switch>
        <Switch name="marketing">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">Marketing emails</Label>
        </Switch>
        <Switch name="social">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">Social media updates</Label>
        </Switch>
      </SwitchGroup.Items>
    </SwitchGroup>
  );
}Group Horizontal
"use client";
import {Label, Switch, SwitchGroup} from "@heroui/react";
export function GroupHorizontal() {
  return (
    <SwitchGroup className="overflow-x-auto" orientation="horizontal">
      <SwitchGroup.Items>
        <Switch name="notifications">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">Notifications</Label>
        </Switch>
        <Switch name="marketing">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">Marketing</Label>
        </Switch>
        <Switch name="social">
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">Social</Label>
        </Switch>
      </SwitchGroup.Items>
    </SwitchGroup>
  );
}Render Props
"use client";
import {Label, Switch} from "@heroui/react";
export function RenderProps() {
  return (
    <Switch>
      {({isSelected}) => (
        <>
          <Switch.Control>
            <Switch.Thumb />
          </Switch.Control>
          <Label className="text-sm">{isSelected ? "Enabled" : "Disabled"}</Label>
        </>
      )}
    </Switch>
  );
}Form Integration
"use client";
import {Button, Label, Switch, SwitchGroup} from "@heroui/react";
import React from "react";
export function Form() {
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);
    alert(
      `Form submitted with:\n${Array.from(formData.entries())
        .map(([key, value]) => `${key}: ${value}`)
        .join("\n")}`,
    );
  };
  return (
    <form className="flex flex-col gap-4" onSubmit={handleSubmit}>
      <SwitchGroup>
        <SwitchGroup.Items>
          <Switch name="notifications" value="on">
            <Switch.Control>
              <Switch.Thumb />
            </Switch.Control>
            <Label className="text-sm">Enable notifications</Label>
          </Switch>
          <Switch defaultSelected name="newsletter" value="on">
            <Switch.Control>
              <Switch.Thumb />
            </Switch.Control>
            <Label className="text-sm">Subscribe to newsletter</Label>
          </Switch>
          <Switch name="marketing" value="on">
            <Switch.Control>
              <Switch.Thumb />
            </Switch.Control>
            <Label className="text-sm">Receive marketing updates</Label>
          </Switch>
        </SwitchGroup.Items>
      </SwitchGroup>
      <Button className="mt-4" size="sm" type="submit" variant="primary">
        Submit
      </Button>
    </form>
  );
}Custom Styles
"use client";
import {Switch} from "@heroui/react";
import {Icon} from "@iconify/react";
export function CustomStyles() {
  return (
    <Switch>
      {({isSelected}) => (
        <>
          <Switch.Control
            className={`h-[31px] w-[51px] bg-blue-500 ${isSelected ? "bg-cyan-500 shadow-[0_0_12px_rgba(6,182,212,0.5)]" : ""}`}
          >
            <Switch.Thumb
              className={`size-[27px] bg-white shadow-sm ${isSelected ? "ms-[22px] shadow-lg" : ""}`}
            >
              <Switch.Icon>
                <Icon
                  className={`size-4 ${isSelected ? "text-cyan-600" : "text-blue-600"}`}
                  icon={isSelected ? "gravity-ui:check" : "gravity-ui:power"}
                />
              </Switch.Icon>
            </Switch.Thumb>
          </Switch.Control>
        </>
      )}
    </Switch>
  );
}Styling
Passing Tailwind CSS classes
import { Switch, Label } from '@heroui/react';
function CustomSwitch() {
  return (
    <Switch>
      {({isSelected}) => (
        <>
          <Switch.Control
            className={`h-[31px] w-[51px] bg-blue-500 ${isSelected ? "bg-cyan-500 shadow-[0_0_12px_rgba(6,182,212,0.5)]" : ""}`}
          >
            <Switch.Thumb
              className={`size-[27px] bg-white shadow-sm ${isSelected ? "translate-x-5 shadow-lg" : ""}`}
            >
              <Switch.Icon>
                <Icon
                  className={`size-4 ${isSelected ? "text-cyan-600" : "text-blue-600"}`}
                  icon={isSelected ? "gravity-ui:check" : "gravity-ui:power"}
                />
              </Switch.Icon>
            </Switch.Thumb>
          </Switch.Control>
        </>
      )}
    </Switch>
  );
}Customizing the component classes
To customize the Switch component classes, you can use the @layer components directive.
Learn more.
@layer components {
  .switch {
    @apply inline-flex gap-3 items-center;
  }
  .switch__control {
    @apply h-5 w-8 bg-gray-400 data-[selected=true]:bg-blue-500;
  }
  .switch__thumb {
    @apply bg-white shadow-sm;
  }
  .switch__icon {
    @apply h-3 w-3 text-current;
  }
}HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The Switch component uses these CSS classes (View source styles):
Base Classes
.switch- Base switch container.switch__control- Switch control track.switch__thumb- Switch thumb that moves.switch__icon- Optional icon inside the thumb
Group Classes
.switch-group- Switch group container.switch-group__items- Container for switch items.switch-group--horizontal- Horizontal layout.switch-group--vertical- Vertical layout
Interactive States
The switch supports both CSS pseudo-classes and data attributes for flexibility:
- Selected: 
[data-selected="true"](thumb position and background color change) - Hover: 
:hoveror[data-hover="true"] - Focus: 
:focus-visibleor[data-focus-visible="true"](shows focus ring) - Disabled: 
:disabledor[aria-disabled="true"](reduced opacity, no pointer events) - Pressed: 
:activeor[data-pressed="true"] 
API Reference
Switch Props
Inherits from React Aria Switch.
| Prop | Type | Default | Description | 
|---|---|---|---|
size | 'sm' | 'md' | 'lg' | 'md' | The size of the switch | 
isSelected | boolean | false | Whether the switch is on | 
defaultSelected | boolean | false | Whether the switch is on by default (uncontrolled) | 
isDisabled | boolean | false | Whether the switch is disabled | 
name | string | - | The name of the input element, used when submitting an HTML form | 
value | string | - | The value of the input element, used when submitting an HTML form | 
onChange | (isSelected: boolean) => void | - | Handler called when the switch value changes | 
onPress | (e: PressEvent) => void | - | Handler called when the switch is pressed | 
children | React.ReactNode | (values: SwitchRenderProps) => React.ReactNode | - | Switch content or render prop | 
SwitchRenderProps
When using the render prop pattern, these values are provided:
| Prop | Type | Description | 
|---|---|---|
isSelected | boolean | Whether the switch is currently on | 
isHovered | boolean | Whether the switch is hovered | 
isPressed | boolean | Whether the switch is currently pressed | 
isFocused | boolean | Whether the switch is focused | 
isFocusVisible | boolean | Whether the switch is keyboard focused | 
isDisabled | boolean | Whether the switch is disabled | 
isReadOnly | boolean | Whether the switch is read only | 
state | - | State of the switch. | 
SwitchGroup Props
| Prop | Type | Default | Description | 
|---|---|---|---|
orientation | 'horizontal' | 'vertical' | 'vertical' | The orientation of the switch group | 
children | React.ReactNode | - | The switch items to render |