Switch

Capture boolean input from user

PackageIcon

Usage

Color
Label position
Size
Radius
import { Switch } from '@mantine/core';

function Demo() {
  return (
    <Switch
      defaultChecked
      label="I agree to sell my privacy"
    />
  );
}

Controlled

import { useState } from 'react';
import { Switch } from '@mantine/core';

function Demo() {
  const [checked, setChecked] = useState(false);
  return (
    <Switch
      checked={checked}
      onChange={(event) => setChecked(event.currentTarget.checked)}
    />
  );
}

Uncontrolled

Switch can be used with uncontrolled forms the same way as a native input[type="checkbox"]. Set the name attribute to include switch value in FormData object on form submission. To control the initial checked state in uncontrolled forms, use defaultChecked prop.

Example usage of uncontrolled Switch with FormData:

import { Switch } from '@mantine/core';

function Demo() {
  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const formData = new FormData(event.currentTarget);
        console.log('Switch value:', !!formData.get('notifications'));
      }}
    >
      <Switch label="Enable notifications" name="notifications" defaultChecked />
      <button type="submit">Submit</button>
    </form>
  );
}

States

import { Switch, Stack } from '@mantine/core';

function Demo() {
  return (
    <Stack>
      <Switch value="value" label="Default switch" />
      <Switch checked value="value" label="Checked switch" />
      <Switch disabled value="value" label="Disabled switch" />
      <Switch checked disabled value="value" label="Disabled checked switch" />
    </Stack>
  );
}

Inner Labels

import { Switch, Group } from '@mantine/core';

function Demo() {
  return (
    <Group justify="center">
      <Switch size="xs" onLabel="ON" offLabel="OFF" />
      <Switch size="sm" onLabel="ON" offLabel="OFF" />
      <Switch size="md" onLabel="ON" offLabel="OFF" />
      <Switch size="lg" onLabel="ON" offLabel="OFF" />
      <Switch size="xl" onLabel="ON" offLabel="OFF" />
    </Group>
  );
}

Icon labels

import { Switch } from '@mantine/core';
import { SunIcon, MoonStarsIcon } from '@phosphor-icons/react';

function Demo() {
  return (
    <Switch
      size="md"
      color="dark.4"
      onLabel={<SunIcon size={16} color="var(--mantine-color-yellow-4)" />}
      offLabel={<MoonStarsIcon size={16} color="var(--mantine-color-blue-6)" />}
    />
  );
}

Thumb icon

import { useState } from 'react';
import { Switch } from '@mantine/core';
import { CheckIcon, XIcon } from '@phosphor-icons/react';

function Demo() {
  const [checked, setChecked] = useState(false);

  return (
    <Switch
      checked={checked}
      onChange={(event) => setChecked(event.currentTarget.checked)}
      color="teal"
      size="md"
      label="Switch with thumb icon"
      thumbIcon={
        checked ? (
          <CheckIcon size={12} color="var(--mantine-color-teal-6)" />
        ) : (
          <XIcon size={12} color="var(--mantine-color-red-6)" />
        )
      }
    />
  );
}

With tooltip

Set refProp="rootRef" on Tooltip and other similar components to make them work with Switch:

import { Switch, Tooltip } from '@mantine/core';

function Demo() {
  return (
    <Tooltip label="Switch tooltip" refProp="rootRef">
      <Switch label="Switch with tooltip" />
    </Tooltip>
  );
}

Pointer cursor

By default, the switch input and label have cursor: default (same as native input[type="checkbox"]). To change the cursor to pointer, set cursorType on the theme:

import { createTheme, MantineProvider, Switch } from '@mantine/core';

const theme = createTheme({
  cursorType: 'pointer',
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Switch label="Pointer cursor" />
    </MantineProvider>
  );
}

Add props to the root element

All props passed to the component are forwarded to the input element. If you need to add props to the root element, use wrapperProps. In the following example:

  • data-testid="wrapper" is added to the root element
  • data-testid="input" is added to the input element
import { Switch } from '@mantine/core';

function Demo() {
  return <Switch wrapperProps={{ 'data-testid': 'wrapper' }} data-testid="input" />;
}

Switch.Group

Select your favorite framework/library

This is anonymous

import { Switch, Group } from '@mantine/core';
function Demo() {
  return (
    <Switch.Group
      defaultValue={['react']}
      label="Select your favorite framework/library"
      description="This is anonymous"
      withAsterisk
    >
      <Group mt="xs">
        <Switch value="react" label="React" />
        <Switch value="svelte" label="Svelte" />
        <Switch value="ng" label="Angular" />
        <Switch value="vue" label="Vue" />
      </Group>
    </Switch.Group>
  );
}

Switch.Group with uncontrolled forms

Switch.Group can be used with uncontrolled forms, it renders a hidden input which joins all checked values into a single string using hiddenInputValuesSeparator prop.

Props for usage with uncontrolled forms:

  • name – name attribute passed to the hidden input
  • hiddenInputValuesSeparator – string used to join checked values into a single string, ',' by default
  • hiddenInputProps – additional props passed to the hidden input
export function UncontrolledForm() {
  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const formData = new FormData(event.currentTarget);
        console.log('Switch group value:', formData.get('frameworks'));
      }}
    >
      <Switch.Group label="Frameworks" name="frameworks" hiddenInputValuesSeparator="|">
        <Switch label="React" value="react" />
        <Switch label="Angular" value="ng" />
      </Switch.Group>
      <button type="submit">Submit</button>
    </form>
  );
}

maxSelectedValues

Use maxSelectedValues prop to limit the number of selected values in Switch.Group. When the limit is reached, the remaining switches are disabled and cannot be selected.

import { Group, Switch } from '@mantine/core';

function Demo() {
  return (
    <Switch.Group defaultValue={['react']} maxSelectedValues={2}>
      <Group>
        <Switch value="react" label="React" />
        <Switch value="svelte" label="Svelte" />
        <Switch value="ng" label="Angular" />
        <Switch value="vue" label="Vue" />
      </Group>
    </Switch.Group>
  );
}

Switch.Group disabled

Select your favorite framework/library

This is anonymous

import { Switch, Group } from '@mantine/core';

function Demo() {
  return (
    <Switch.Group
      disabled
      label="Select your favorite framework/library"
      description="This is anonymous"
    >
      <Group mt="xs">
        <Switch value="react" label="React" />
        <Switch value="svelte" label="Svelte" />
        <Switch value="ng" label="Angular" />
        <Switch value="vue" label="Vue" />
      </Group>
    </Switch.Group>
  );
}

Controlled Switch.Group

import { useState } from 'react';
import { Switch } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState<string[]>([]);

  return (
    <Switch.Group value={value} onChange={setValue}>
      <Switch value="react" label="React" />
      <Switch value="svelte" label="Svelte" />
    </Switch.Group>
  );
}

Change styles based on checked state

.track {
  transition:
    background-color 200ms ease,
    border-color 200ms ease;

  input:checked + & {
    background-color: var(--mantine-color-lime-5);
    border-color: var(--mantine-color-lime-5);

    & > .thumb {
      background-color: var(--mantine-color-black);

      &::before {
        background-color: var(--mantine-color-lime-5);
      }
    }
  }
}

Styles API

Switch supports the Styles API; you can add styles to any inner element of the component with the classNames prop. Follow the Styles API documentation to learn more.

Component Styles API

Hover over selectors to highlight corresponding elements

/*
 * Hover over selectors to apply outline styles
 *
 */

Get input ref

import { useRef } from 'react';
import { Switch } from '@mantine/core';

function Demo() {
  const ref = useRef<HTMLInputElement>(null);
  return <Switch ref={ref} />;
}

Accessibility

Switch is a regular input[type="checkbox"]. Set aria-label if the Switch is used without the label prop:

import { Switch } from '@mantine/core';

// -> not ok, input is not labeled
function Bad() {
  return <Switch />;
}

// -> ok, input has aria-label
function Good() {
  return <Switch aria-label="I agree to everything" />;
}

// -> ok, input has associated label
function AlsoGood() {
  return <Switch label="I agree to everything" />;
}