> ## Documentation Index
> Fetch the complete documentation index at: https://www.beeq.design/llms.txt
> Use this file to discover all available pages before exploring further.

# Switch

> Switches are digital on/off toggles that give users immediate, visible control over a single binary setting without requiring form submission.

export const CodeLivePreview = ({code, children, height, removePadding = false, mode = 'shadow'}) => {
  const previewRef = useRef(null);
  const BEEQ_ESM_URL = 'https://esm.sh/@beeq/core/dist/beeq/beeq.esm.js';
  const BEEQ_CSS_URL = 'https://esm.sh/@beeq/core/dist/beeq/beeq.css';
  const BEEQ_ICONS_URL = 'https://esm.sh/@beeq/core/dist/beeq/svg';
  const ensureParentBeeqRuntime = () => {
    if (document.querySelector('script[data-beeq-parent-runtime]')) return;
    const script = document.createElement('script');
    script.type = 'module';
    script.src = BEEQ_ESM_URL;
    script.dataset.beeqParentRuntime = BEEQ_ICONS_URL;
    document.head.appendChild(script);
  };
  const executeSnippetScripts = (root, runtimeWindow, previewRootArg, skipAttr) => {
    root.querySelectorAll('script').forEach(oldScript => {
      if (skipAttr && oldScript.hasAttribute(skipAttr)) return;
      if (oldScript.src) {
        const newScript = runtimeWindow.document.createElement('script');
        newScript.src = oldScript.src;
        oldScript.replaceWith(newScript);
        return;
      }
      runtimeWindow.Function('previewRoot', oldScript.textContent || '')(previewRootArg);
      oldScript.remove();
    });
  };
  const syncIframeMode = iframeDoc => {
    const root = document.documentElement;
    const explicitMode = root.getAttribute('bq-mode');
    const isDark = root.classList.contains('dark');
    const resolvedMode = explicitMode || (isDark ? 'dark' : 'light');
    iframeDoc.documentElement.setAttribute('bq-mode', resolvedMode);
    iframeDoc.body.setAttribute('bq-mode', resolvedMode);
  };
  useEffect(() => {
    if (mode === 'shadow') ensureParentBeeqRuntime();
  }, [mode]);
  useEffect(() => {
    const container = previewRef.current;
    if (!container) return;
    if (removePadding) container.style.padding = '0';
    container.innerHTML = '';
    if (mode === 'iframe') {
      const iframe = document.createElement('iframe');
      iframe.className = 'preview-iframe';
      iframe.style.width = '100%';
      iframe.style.border = '0';
      iframe.style.display = 'block';
      iframe.style.minHeight = height ?? '0px';
      iframe.setAttribute('title', 'Live code preview');
      iframe.setAttribute('loading', 'lazy');
      iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
      container.appendChild(iframe);
      const iframeDoc = iframe.contentDocument;
      const iframeWin = iframe.contentWindow;
      if (!iframeDoc || !iframeWin) return;
      iframeDoc.open();
      iframeDoc.write(['<!doctype html>', '<html>', '<head>', '  <meta charset="utf-8" />', '  <meta name="viewport" content="width=device-width, initial-scale=1" />', '  <style>html,body{margin:0;padding:0;min-height:100%;}</style>', `  <link rel="stylesheet" href="${BEEQ_CSS_URL}" />`, `  <script type="module" src="${BEEQ_ESM_URL}" data-beeq-iframe-runtime="${BEEQ_ICONS_URL}"></script>`, '</head>', '<body>', code, '</body>', '</html>'].join('\n'));
      iframeDoc.close();
      syncIframeMode(iframeDoc);
      const modeObserver = new MutationObserver(() => syncIframeMode(iframeDoc));
      modeObserver.observe(document.documentElement, {
        attributes: true,
        attributeFilter: ['class', 'bq-mode']
      });
      executeSnippetScripts(iframeDoc, iframeWin, iframeDoc, 'data-beeq-iframe-runtime');
      return () => modeObserver.disconnect();
    }
    const shadowRoot = container.shadowRoot ?? container.attachShadow({
      mode: 'open'
    });
    if (!shadowRoot.adoptedStyleSheets.length) {
      const fixSheet = new CSSStyleSheet();
      fixSheet.replaceSync(`
        bq-dropdown::part(panel),
        bq-panel::part(panel),
        bq-select::part(panel),
        bq-date-picker::part(panel) { z-index: 9999; }
        bq-tooltip::part(panel) { position: absolute; }
      `);
      shadowRoot.adoptedStyleSheets = [fixSheet];
    }
    shadowRoot.innerHTML = [`<link rel="stylesheet" href="${BEEQ_CSS_URL}">`, code].join('');
    executeSnippetScripts(shadowRoot, window, shadowRoot);
    return undefined;
  }, [code, mode, height]);
  return <div className="code-live-preview not-prose">
      {}
      <div className="preview" ref={previewRef} style={{
    minHeight: height
  }} />

      {}
      {children && <div className="code">{children}</div>}
    </div>;
};

<Frame className="px-4 py-4" caption="Switch component overview">
  <img className="block dark:hidden" src="https://mintlify.s3.us-west-1.amazonaws.com/beeq/components/images/switch/switch-overview-light.svg" alt="BEEQ Switch component overview" />

  <img className="hidden dark:block" src="https://mintlify.s3.us-west-1.amazonaws.com/beeq/components/images/switch/switch-overview-dark.svg" alt="BEEQ Switch component overview" />
</Frame>

A switch is a binary control that immediately toggles a setting on or off. Unlike checkboxes, a switch should trigger an instant change — no submit button needed. Use it for toggling preferences, enabling features, or activating modes where the result is visible right away.

<Note>
  Use a [Checkbox](/components/checkbox) when the choice is part of a form that requires explicit submission, or when multiple items can be selected at once. Use a Switch when the action takes immediate effect.
</Note>

## When to use

<CardGroup cols={2}>
  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="thumbs-up" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Use a switch when
    </span>

    * Toggling a single setting that takes effect immediately
    * The on/off state directly controls a feature, mode, or preference
    * The action does not require a separate confirmation or form submission
    * You need a compact, recognizable binary control
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="thumbs-down" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Do not use a switch when
    </span>

    * The setting only takes effect after the user clicks a Save or Submit button
    * Multiple related options need to be selected together (use checkboxes)
    * The action is irreversible and needs a confirmation step
    * The label text does not clearly describe the result of toggling
  </Card>
</CardGroup>

## Anatomy

<Frame className="px-4 py-4" caption="Switch component anatomy">
  <img className="block dark:hidden" src="https://mintlify.s3.us-west-1.amazonaws.com/beeq/components/images/switch/switch-anatomy-light.svg" alt="BEEQ Switch component anatomy" />

  <img className="hidden dark:block" src="https://mintlify.s3.us-west-1.amazonaws.com/beeq/components/images/switch/switch-anatomy-dark.svg" alt="BEEQ Switch component anatomy" />
</Frame>

The switch is composed of a toggle control (track + dot) and an optional label. When `inner-label` is set to `icon`, check and X marks appear inside the track to reinforce the on/off state.

| Part  | Element       | Description                                                                   |
| ----- | ------------- | ----------------------------------------------------------------------------- |
| **1** | Switch toggle | The rounded track and sliding dot that act as the toggle surface              |
| **2** | Icon          | Optional icon inside the track to reinforce the on/off state (icon mode only) |
| **3** | Label         | Optional text describing what the switch controls                             |

## Design guidelines

### States

A switch has four interactive states: **default** (off), **checked** (on), **focused**, and **disabled**. Hover adds a subtle background when `background-on-hover` is enabled. The disabled state prevents all interaction and dims the control to signal it is unavailable.

<Note>
  Always pair a switch with a visible text label unless the context makes the purpose unmistakably clear (for example, a dark-mode toggle adjacent to sun and moon icons). Unlabeled switches are inaccessible by default.
</Note>

### Inner label

<Steps>
  <Step title="Default (no inner label)">
    The track contains only the sliding dot. This is the most compact presentation and works well in dense settings panels.
  </Step>

  <Step title="Icon inner label">
    Set `inner-label="icon"` to show a check icon when ON and an X icon when OFF inside the track. This adds a secondary visual reinforcement of the state without relying on color alone.
  </Step>

  <Step title="Custom icon slots">
    Replace the default icons by providing content to the `icon-on` and `icon-off` named slots alongside `inner-label="icon"`. Use this for domain-specific icons such as a moon/sun pair for a dark-mode toggle.
  </Step>
</Steps>

### Label position

By default, the label appears to the right of the control. Set `reverse-order` to move it to the left — useful in right-to-left layouts or when a consistent label-first alignment is required across a settings list.

## Usage

### Default

The default switch provides a basic on/off toggle functionality, allowing users to control a binary state effortlessly.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-switch>Toggle me!</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch>Toggle me!</bq-switch>
    ```

    ```tsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqSwitch } from "@beeq/react";

    export default () => (
      <BqSwitch>Toggle me!</BqSwitch>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqSwitch],
      template: `<bq-switch>Toggle me!</bq-switch>`,
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch>Toggle me!</BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

<Tip>
  You don't need to specify any additional property or attribute that uses its default value.
</Tip>

### Checked

Use the `checked` attribute to set the initial state of the toggle as ON. This is ideal when you want the switch to start in an activated position.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-switch checked>Toggle me!</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch checked>Toggle me!</bq-switch>
    ```

    ```tsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqSwitch } from "@beeq/react";

    export default () => (
      <BqSwitch checked>Toggle me!</BqSwitch>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqSwitch],
      template: `<bq-switch checked>Toggle me!</bq-switch>`,
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch checked>Toggle me!</BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

## Options

### Disabled

The disabled switch prevents user interaction, making it visually clear that the toggle functionality is not currently available or applicable. Use the `disabled` attribute to enable this type of switch.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-switch disabled>Toggle me!</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch disabled>Toggle me!</bq-switch>
    ```

    ```tsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqSwitch } from "@beeq/react";

    export default () => (
      <BqSwitch disabled>Toggle me!</BqSwitch>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqSwitch],
      template: `<bq-switch disabled>Toggle me!</bq-switch>`,
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch disabled>Toggle me!</BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### With inner label

Enhance user understanding by incorporating an inner label that provides context about the current state of the switch. Use the `inner-label="icon"` attribute to activate this variant.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-switch inner-label="icon">Toggle me!</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch inner-label="icon">Toggle me!</bq-switch>
    ```

    ```tsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqSwitch } from "@beeq/react";

    export default () => (
      <BqSwitch innerLabel="icon">Toggle me!</BqSwitch>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqSwitch],
      template: `<bq-switch inner-label="icon">Toggle me!</bq-switch>`,
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch innerLabel="icon">Toggle me!</BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Custom icons

Use the `icon-on` and `icon-off` slots to replace the default check and X marks. The slots render inside the track when `inner-label="icon"` is enabled.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-switch checked inner-label="icon" name="theme-mode">
<bq-icon slot="icon-on" name="moon" size="16"></bq-icon>
<bq-icon slot="icon-off" name="sun" size="16"></bq-icon>
Dark mode
</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch checked inner-label="icon" name="theme-mode">
      <bq-icon slot="icon-on" name="moon" size="16"></bq-icon>
      <bq-icon slot="icon-off" name="sun" size="16"></bq-icon>
      Dark mode
    </bq-switch>
    ```

    ```tsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqIcon, BqSwitch } from "@beeq/react";

    export default () => (
      <BqSwitch checked innerLabel="icon" name="theme-mode">
        <BqIcon slot="icon-on" name="moon" size="16" />
        <BqIcon slot="icon-off" name="sun" size="16" />
        Dark mode
      </BqSwitch>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqIcon, BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqIcon, BqSwitch],
      template: `
        <bq-switch checked inner-label="icon" name="theme-mode">
          <bq-icon slot="icon-on" name="moon" size="16"></bq-icon>
          <bq-icon slot="icon-off" name="sun" size="16"></bq-icon>
          Dark mode
        </bq-switch>
      `,
    })
    export class ThemeSwitchComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqIcon, BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch checked innerLabel="icon" name="theme-mode">
        <BqIcon slot="icon-on" name="moon" size="16" />
        <BqIcon slot="icon-off" name="sun" size="16" />
        Dark mode
      </BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

<Tip>
  Mind the icon size. It should be consistent with the switch size.
</Tip>

### Reverse order

The reverse order switch alters the visual arrangement, placing the toggle on the opposite side for a customizable user interface by adding the `reverse-order` attribute.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-switch reverse-order>Toggle me!</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch reverse-order>Toggle me!</bq-switch>
    ```

    ```tsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqSwitch } from "@beeq/react";

    export default () => (
      <BqSwitch reverseOrder>Toggle me!</BqSwitch>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqSwitch],
      template: `<bq-switch reverse-order>Toggle me!</bq-switch>`,
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch reverseOrder>Toggle me!</BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Full width

Use `full-width` with `reverse-order` and `justify-content="space-between"` to build standard settings-list rows where the label is on the left and the toggle sits flush to the right edge.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  flex-direction: column !important;
  align-items: stretch !important;
  max-width: 28rem;
}
</style>

<bq-switch
background-on-hover
full-width
justify-content="space-between"
name="bq-switch"
reverse-order
value="show-app-list"
>
Show app list in menu
</bq-switch>
<bq-switch
background-on-hover
checked
full-width
justify-content="space-between"
name="bq-switch"
reverse-order
value="show-recently-apps"
>
Show recently added apps
</bq-switch>
<bq-switch
background-on-hover
disabled
full-width
justify-content="space-between"
name="bq-switch"
reverse-order
value="show-used-apps"
>
Show most used apps
</bq-switch>
<bq-switch
background-on-hover
checked
full-width
justify-content="space-between"
name="bq-switch"
reverse-order
value="show-app-notifications"
>
Show app notifications
</bq-switch>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-switch
      background-on-hover
      full-width
      justify-content="space-between"
      name="bq-switch"
      reverse-order
      value="show-app-list"
    >
      Show app list in menu
    </bq-switch>
    <bq-switch
      background-on-hover
      checked
      full-width
      justify-content="space-between"
      name="bq-switch"
      reverse-order
      value="show-recently-apps"
    >
      Show recently added apps
    </bq-switch>
    <bq-switch
      background-on-hover
      disabled
      full-width
      justify-content="space-between"
      name="bq-switch"
      reverse-order
      value="show-used-apps"
    >
      Show most used apps
    </bq-switch>
    <bq-switch
      background-on-hover
      checked
      full-width
      justify-content="space-between"
      name="bq-switch"
      reverse-order
      value="show-app-notifications"
    >
      Show app notifications
    </bq-switch>
    ```

    ```tsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqSwitch } from "@beeq/react";

    export default () => (
      <>
        <BqSwitch
          backgroundOnHover
          fullWidth
          justifyContent="space-between"
          name="bq-switch"
          reverseOrder
          value="show-app-list"
        >
          Show app list in menu
        </BqSwitch>
        <BqSwitch
          backgroundOnHover
          checked
          fullWidth
          justifyContent="space-between"
          name="bq-switch"
          reverseOrder
          value="show-recently-apps"
        >
          Show recently added apps
        </BqSwitch>
        <BqSwitch
          backgroundOnHover
          disabled
          fullWidth
          justifyContent="space-between"
          name="bq-switch"
          reverseOrder
          value="show-used-apps"
        >
          Show most used apps
        </BqSwitch>
        <BqSwitch
          backgroundOnHover
          checked
          fullWidth
          justifyContent="space-between"
          name="bq-switch"
          reverseOrder
          value="show-app-notifications"
        >
          Show app notifications
        </BqSwitch>
      </>
    );
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqSwitch],
      template: `
        <bq-switch
          background-on-hover
          full-width
          justify-content="space-between"
          name="bq-switch"
          reverse-order
          value="show-app-list"
        >
          Show app list in menu
        </bq-switch>
        <bq-switch
          background-on-hover
          checked
          full-width
          justify-content="space-between"
          name="bq-switch"
          reverse-order
          value="show-recently-apps"
        >
          Show recently added apps
        </bq-switch>
        <bq-switch
          background-on-hover
          disabled
          full-width
          justify-content="space-between"
          name="bq-switch"
          reverse-order
          value="show-used-apps"
        >
          Show most used apps
        </bq-switch>
        <bq-switch
          background-on-hover
          checked
          full-width
          justify-content="space-between"
          name="bq-switch"
          reverse-order
          value="show-app-notifications"
        >
          Show app notifications
        </bq-switch>
      `,
    })
    export class AppComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqSwitch } from "@beeq/vue";
    </script>

    <template>
      <BqSwitch
        backgroundOnHover
        fullWidth
        justifyContent="space-between"
        name="bq-switch"
        reverseOrder
        value="show-app-list"
      >
        Show app list in menu
      </BqSwitch>
      <BqSwitch
        backgroundOnHover
        checked
        fullWidth
        justifyContent="space-between"
        name="bq-switch"
        reverseOrder
        value="show-recently-apps"
      >
        Show recently added apps
      </BqSwitch>
      <BqSwitch
        backgroundOnHover
        disabled
        fullWidth
        justifyContent="space-between"
        name="bq-switch"
        reverseOrder
        value="show-used-apps"
      >
        Show most used apps
      </BqSwitch>
      <BqSwitch
        backgroundOnHover
        checked
        fullWidth
        justifyContent="space-between"
        name="bq-switch"
        reverseOrder
        value="show-app-notifications"
      >
        Show app notifications
      </BqSwitch>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

<Tip>
  Use a combination of `full-width`, `justify-content`, and `reverse-order`. Be creative!
</Tip>

### Form integration

`bq-switch` participates in native forms through `ElementInternals`. A checked switch submits `"on"` for its `name`; an unchecked switch is omitted from `FormData`. Use `required` only when the form cannot continue unless the switch is ON.

<CodeLivePreview
  mode="iframe"
  height="23rem"
  removePadding
  code={`
<style>
body {
  padding: var(--bq-spacing-l);
}

.switch-form {
  display: grid;
  gap: var(--bq-spacing-m);
}

.switch-form__actions {
  display: flex;
  gap: var(--bq-spacing-s);
  justify-content: flex-end;
}

.switch-form__output {
  margin: 0;
  padding: var(--bq-spacing-s);
  border: var(--bq-stroke-s) solid var(--bq-stroke--tertiary);
  border-radius: var(--bq-radius--s);
  background: var(--bq-ui--secondary);
  color: var(--bq-text--primary);
  white-space: pre-wrap;
}
</style>

<form class="switch-form" id="switch-form">
<bq-switch
  checked
  form-validation-message="Enable release alerts to continue"
  inner-label="icon"
  name="releaseAlerts"
  required
>
  Release alerts
</bq-switch>
<div class="switch-form__actions">
  <bq-button appearance="secondary" type="reset">Reset</bq-button>
  <bq-button type="button">Save</bq-button>
</div>
<pre class="switch-form__output" id="switch-output">{}</pre>
</form>

<script>
(() => {
  const form = previewRoot.querySelector('#switch-form');
  const output = previewRoot.querySelector('#switch-output');
  const submitButton = form.querySelector('bq-button[type="button"]');

  const showFormData = () => {
    if (!form.reportValidity()) return;
    output.textContent = JSON.stringify(Object.fromEntries(new FormData(form).entries()), null, 2);
  };

  submitButton?.addEventListener('bqClick', (event) => {
    event.preventDefault();
    showFormData();
  });

  form.addEventListener('submit', (event) => {
    event.preventDefault();
    showFormData();
  });

  form.addEventListener('reset', () => {
    requestAnimationFrame(() => {
      output.textContent = '{}';
    });
  });
})();
</script>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <form id="switch-form">
      <bq-switch
        checked
        form-validation-message="Enable release alerts to continue"
        inner-label="icon"
        name="releaseAlerts"
        required
      >
        Release alerts
      </bq-switch>
      <bq-button appearance="secondary" type="reset">Reset</bq-button>
      <bq-button type="submit">Save</bq-button>
      <pre id="switch-output">{}</pre>
    </form>

    <script>
      const form = document.querySelector('#switch-form');
      const output = document.querySelector('#switch-output');

      form.addEventListener('submit', (event) => {
        event.preventDefault();
        output.textContent = JSON.stringify(Object.fromEntries(new FormData(form).entries()), null, 2);
      });

      form.addEventListener('reset', () => {
        requestAnimationFrame(() => {
          output.textContent = '{}';
        });
      });
    </script>
    ```

    ```tsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { useState } from "react";
    import { BqButton, BqSwitch } from "@beeq/react";

    export default function SwitchForm() {
      const [data, setData] = useState("{}");

      return (
        <form
          onReset={() => setData("{}")}
          onSubmit={(event) => {
            event.preventDefault();
            setData(JSON.stringify(Object.fromEntries(new FormData(event.currentTarget).entries()), null, 2));
          }}
        >
          <BqSwitch
            checked
            formValidationMessage="Enable release alerts to continue"
            innerLabel="icon"
            name="releaseAlerts"
            required
          >
            Release alerts
          </BqSwitch>
          <BqButton appearance="secondary" type="reset">Reset</BqButton>
          <BqButton type="submit">Save</BqButton>
          <pre>{data}</pre>
        </form>
      );
    }
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqButton, BqSwitch } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqButton, BqSwitch],
      template: `
        <form (reset)="data = '{}'" (submit)="handleSubmit($event)">
          <bq-switch
            checked
            form-validation-message="Enable release alerts to continue"
            inner-label="icon"
            name="releaseAlerts"
            required
          >
            Release alerts
          </bq-switch>
          <bq-button appearance="secondary" type="reset">Reset</bq-button>
          <bq-button type="submit">Save</bq-button>
          <pre>{{ data }}</pre>
        </form>
      `,
    })
    export class SwitchFormComponent {
      data = "{}";

      handleSubmit(event: SubmitEvent): void {
        event.preventDefault();
        this.data = JSON.stringify(Object.fromEntries(new FormData(event.target as HTMLFormElement).entries()), null, 2);
      }
    }
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { ref } from "vue";
    import { BqButton, BqSwitch } from "@beeq/vue";

    const data = ref("{}");

    function handleSubmit(event: Event) {
      data.value = JSON.stringify(Object.fromEntries(new FormData(event.target as HTMLFormElement).entries()), null, 2);
    }
    </script>

    <template>
      <form @reset="data = '{}'" @submit.prevent="handleSubmit">
        <BqSwitch
          checked
          formValidationMessage="Enable release alerts to continue"
          innerLabel="icon"
          name="releaseAlerts"
          required
        >
          Release alerts
        </BqSwitch>
        <BqButton appearance="secondary" type="reset">Reset</BqButton>
        <BqButton type="submit">Save</BqButton>
        <pre>{{ data }}</pre>
      </form>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

## Best practices

<CardGroup cols={2}>
  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Use concise, present-tense labels that clearly describe the result of the switch being on. "Enable notifications" or "Dark mode" communicate the outcome at a glance.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Use vague labels like "Toggle" or "On/Off". Users should not need to think about what the switch controls — the label must describe the setting itself.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Apply the switch's effect immediately without requiring a submit action. Use this pattern for preferences that take effect in real time — dark mode, notifications, or feature flags.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Use a switch when the change only takes effect after the user clicks a Save button. If the state is not immediately applied, use a checkbox inside a form instead.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Use `inner-label="icon"` to supplement the color change with a shape cue (check / X). This improves the control for users with color vision deficiencies who cannot rely on brand color alone.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Rely solely on the track color to communicate the ON state. Always ensure that at least one additional cue — dot position or icon — distinguishes the two states.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Place the label directly adjacent to the switch and keep the pairing stable across the list. Consistent label position helps users scan a settings panel without searching for the control.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Change the label text based on state (for example, "Enabled" when on and "Disabled" when off). The label should always describe the setting — the control itself communicates the current state.
  </Card>
</CardGroup>

## Accessibility

`bq-switch` renders a native `<input type="checkbox" role="switch">` inside its shadow DOM, which ensures that assistive technologies correctly announce the control as a switch with an on/off state.

### Keyboard interaction

| Key     | Action                       |
| ------- | ---------------------------- |
| `Tab`   | Moves focus to the switch    |
| `Space` | Toggles the switch on or off |

### Developer responsibilities

* Always provide a visible text label via the default slot. The switch derives its accessible name from the `name` prop via `aria-label` on the native `<input>` — the visible slot text is not automatically wired to the control. If you want the visible label to serve as the accessible name, use `aria-labelledby` on the host element pointing to the associated label element.
* Use the `name` attribute (required) to participate in form submissions and to give the control a machine-readable identifier.
* When the switch is `disabled`, it is excluded from the tab order and will not respond to keyboard or pointer events. Make sure the reason for disabling is communicated through surrounding text.
* The `bqChange` event is cancelable. Calling `event.preventDefault()` inside a `bqChange` handler prevents the switch from updating its visual state, which is useful when you need to confirm a change before applying it.
* Use `vFocus()`, `vBlur()`, and `vClick()` instead of the global `element.focus()`, `element.blur()`, and `element.click()` to interact with the native input correctly across Shadow DOM boundaries.

## API reference

### Properties

| Property                | Attribute                 | Description                                                                                                                                                            | Type                                                                                                                                                                                        | Default      |
| ----------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| `backgroundOnHover`     | `background-on-hover`     | If `true`, a background is shown on hover                                                                                                                              | `boolean`                                                                                                                                                                                   | `false`      |
| `checked`               | `checked`                 | If `true`, the switch starts in the ON state                                                                                                                           | `boolean`                                                                                                                                                                                   | `false`      |
| `disabled`              | `disabled`                | If `true`, the switch is disabled and non-interactive                                                                                                                  | `boolean`                                                                                                                                                                                   | `false`      |
| `formValidationMessage` | `form-validation-message` | Custom native form validation message                                                                                                                                  | `string`                                                                                                                                                                                    | —            |
| `fullWidth`             | `full-width`              | If `true`, the switch expands to fill its container                                                                                                                    | `boolean`                                                                                                                                                                                   | `false`      |
| `innerLabel`            | `inner-label`             | How to display the on/off marks inside the control                                                                                                                     | `'default' \| 'icon'`                                                                                                                                                                       | `'default'`  |
| `justifyContent`        | `justify-content`         | Space distribution between the control and label; accepts any `justify-content` value                                                                                  | `'start' \| 'end' \| 'center' \| 'flex-start' \| 'flex-end' \| 'left' \| 'right' \| 'space-between' \| 'space-around' \| 'space-evenly' \| 'stretch' \| 'normal' \| 'inherit' \| 'initial'` | `'start'`    |
| `name`                  | `name`                    | Form control name; submitted as part of a name/value pair                                                                                                              | `string`                                                                                                                                                                                    | **required** |
| `required`              | `required`                | If `true`, the switch must be ON before the form can be submitted                                                                                                      | `boolean`                                                                                                                                                                                   | `false`      |
| `reverseOrder`          | `reverse-order`           | If `true`, the label appears before the control                                                                                                                        | `boolean`                                                                                                                                                                                   | `false`      |
| `value`                 | `value`                   | Sets the underlying `<input>` value attribute. Note: the form submission value is the fixed string `'on'` when checked (via ElementInternals), regardless of this prop | `string`                                                                                                                                                                                    | —            |

### Methods

| Method     | Description                                       | Signature       |
| ---------- | ------------------------------------------------- | --------------- |
| `vBlur()`  | Removes focus from the native `<input>` element   | `Promise<void>` |
| `vClick()` | Simulates a click on the native `<input>` element | `Promise<void>` |
| `vFocus()` | Sets focus on the native `<input>` element        | `Promise<void>` |

### Events

| Event      | Description                                                                    | Type                                |
| ---------- | ------------------------------------------------------------------------------ | ----------------------------------- |
| `bqBlur`   | Emitted when the switch loses focus                                            | `CustomEvent<HTMLBqSwitchElement>`  |
| `bqChange` | Emitted when the switch state changes; cancelable via `event.preventDefault()` | `CustomEvent<{ checked: boolean }>` |
| `bqFocus`  | Emitted when the switch gains focus                                            | `CustomEvent<HTMLBqSwitchElement>`  |

### Slots

| Slot        | Description                                                                               |
| ----------- | ----------------------------------------------------------------------------------------- |
| *(default)* | The label text displayed next to the control                                              |
| `icon-on`   | Custom icon shown inside the track when the switch is ON (requires `inner-label="icon"`)  |
| `icon-off`  | Custom icon shown inside the track when the switch is OFF (requires `inner-label="icon"`) |

### Shadow parts

| Part       | Description                                                   |
| ---------- | ------------------------------------------------------------- |
| `base`     | The `<label>` root container element                          |
| `control`  | The `<div>` element that forms the toggle track               |
| `dot`      | The `<div>` element that acts as the sliding indicator dot    |
| `icon-on`  | The `<bq-icon>` element used as the ON mark (icon mode only)  |
| `icon-off` | The `<bq-icon>` element used as the OFF mark (icon mode only) |
| `label`    | The `<span>` element that holds the label text                |

### CSS custom properties

| Variable                       | Description                                      | Default                                                        |
| ------------------------------ | ------------------------------------------------ | -------------------------------------------------------------- |
| `--bq-switch--height`          | Height of the switch track                       | `24px`                                                         |
| `--bq-switch--width`           | Width of the switch track                        | `44px`                                                         |
| `--bq-switch--dot-size`        | Diameter of the sliding dot                      | `calc(var(--bq-switch--height) - (var(--bq-spacing-xs2) * 2))` |
| `--bq-switch--justify-content` | Space distribution between the control and label | `start`                                                        |

<Tip>
  Learn more about [styling with shadow parts](/guides/styles) and [CSS custom properties](/theming/global-css-variables).
</Tip>

## Resources

<CardGroup cols={2}>
  <Card horizontal title="Interactive playground" icon="code" href="https://storybook.beeq.design/?path=/story/components-switch--default">
    Explore switch variants and states in Storybook
  </Card>

  <Card horizontal title="Source code" icon="github" href="https://github.com/Endava/BEEQ/tree/main/packages/beeq/src/components/switch">
    View the component source on GitHub
  </Card>
</CardGroup>
