Skip to main content

Theme config

Theme mode

Color palette

Grays

Border radii/radiuses/radiopedes/you know
Border radius
Field border radius
Button border radius
All
Components
Guides
API
Recent

    Components

    Switch

    See also: Switch field group.

    Full supportSupported since v123.Full supportSupported since v121.Full supportSupported since v17.5.

    Anatomy

    • <Switch>

      Container element.

    • <input>

      The switch input.

    • slot="icon-unchecked"

      An optional icon in the thumb when unchecked.

    • slot="icon-checked"

      An optional icon in the thumb when checked.

    • slot="default"

      The label.

    • slot="end-text"

      Supporting text displayed below the label.

    All switches should have an accessible name. Either provide a visible or visually-hidden label inside the component, or set aria-label on the input. Both approaches are fine.

    ---
    import { Switch } from "@opui/astro"
    ---
    <Switch name="switch-variants" checked hideLabel>Label</Switch>
    <Switch name="switch-variants" hideLabel>Label</Switch>
    <Switch name="switch-variants" checked disabled hideLabel>Label</Switch>
    <Switch name="switch-variants" disabled hideLabel>Label</Switch>
    <label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-variants" checked /><span
    class="ui-sr-only"
    >Label</span
    ></label
    ><label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-variants" /><span
    class="ui-sr-only"
    >Label</span
    ></label
    ><label class="ui-switch"
    ><input
    type="checkbox"
    role="switch"
    name="switch-variants"
    checked
    disabled
    /><span class="ui-sr-only">Label</span></label
    ><label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-variants" disabled /><span
    class="ui-sr-only"
    >Label</span
    ></label
    >

    Visible label

    Render the label text inside an element with a .ui-label class. Also, don't miss the info on label accessibility.

    ---
    import { Switch } from "@opui/astro"
    ---
    <Switch name="switch-visible-label">Label</Switch>
    <Switch name="switch-visible-label" disabled>Disabled</Switch>
    <Switch name="switch-visible-label">
    Long text bacon ipsum dolor amet prosciutto tenderloin biltong leberkas ribeye
    short ribs shankle tri-tip doner buffalo chislic meatloaf meatball.
    </Switch>
    <label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-visible-label" /><span
    class="ui-label"
    >Label</span
    ></label
    ><label class="ui-switch"
    ><input
    type="checkbox"
    role="switch"
    name="switch-visible-label"
    disabled
    /><span class="ui-label">Disabled</span></label
    ><label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-visible-label" /><span
    class="ui-label"
    >Long text bacon ipsum dolor amet prosciutto tenderloin biltong leberkas
    ribeye short ribs shankle tri-tip doner buffalo chislic meatloaf
    meatball.</span
    ></label
    >

    Label position

    ---
    import { Switch } from "@opui/astro"
    ---
    <Switch name="switch-label-position">Default</Switch>
    <Switch name="switch-label-position" stack>Stack</Switch>
    <label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-label-position" /><span
    class="ui-label"
    >Default</span
    ></label
    ><label class="ui-switch ui-stack"
    ><input type="checkbox" role="switch" name="switch-label-position" /><span
    class="ui-label"
    >Stack</span
    ></label
    >

    End text

    ---
    import { Switch } from "@opui/astro"
    ---
    <Switch name="switch-supporting-text">
    Default
    <Fragment slot="end-text">Supporting text</Fragment>
    </Switch>
    <Switch name="switch-supporting-text" stack>
    Stack
    <Fragment slot="end-text">Supporting text</Fragment>
    </Switch>
    <label class="ui-switch"
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-2"
    name="switch-supporting-text"
    /><span class="ui-label">Default</span
    ><span id="end-text-2" class="ui-end-text">Supporting text</span></label
    ><label class="ui-switch ui-stack"
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-3"
    name="switch-supporting-text"
    /><span class="ui-label">Stack</span
    ><span id="end-text-3" class="ui-end-text">Supporting text</span></label
    >

    Validation

    • Set required on the component to toggle required styles on the input.
    • Use the error prop to toggle invalid styles. It rendersdata-invalid on the root element. Make use of the end text to give extra feedback on the error.
    ---
    import { Switch } from "@opui/astro"
    ---
    <div class="example-row ui-spacious">
    <Switch name="switch-validation" required>Default</Switch>
    <Switch name="switch-validation" required stack>Stack</Switch>
    </div>
    <div class="example-row ui-spacious">
    <Switch name="switch-validation" error>
    Default
    <Fragment slot="end-text">Supporting text</Fragment>
    </Switch>
    <Switch name="switch-validation" error stack>
    Stack
    <Fragment slot="end-text">Supporting text</Fragment>
    </Switch>
    </div>
    <div class="example-row ui-spacious">
    <label class="ui-switch"
    ><input
    type="checkbox"
    role="switch"
    name="switch-validation"
    required
    /><span class="ui-label">Default</span></label
    ><label class="ui-switch ui-stack"
    ><input
    type="checkbox"
    role="switch"
    name="switch-validation"
    required
    /><span class="ui-label">Stack</span></label
    >
    </div>
    <div class="example-row ui-spacious">
    <label class="ui-switch" data-invalid
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-4"
    name="switch-validation"
    /><span class="ui-label">Default</span
    ><span id="end-text-4" class="ui-end-text">Supporting text</span></label
    ><label class="ui-switch ui-stack" data-invalid
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-5"
    name="switch-validation"
    /><span class="ui-label">Stack</span
    ><span id="end-text-5" class="ui-end-text">Supporting text</span></label
    >
    </div>

    Spread

    Use the spread prop to push the label to the left and the switch to the right. This is useful for full-width items like lists and menus.

    ---
    import { Switch } from "@opui/astro"
    ---
    <Switch name="switch-spread" spread>
    Notifications
    <Fragment slot="end-text">Receive alerts when someone mentions you.</Fragment>
    </Switch>
    <Switch name="switch-spread" spread required>
    Required
    <Fragment slot="end-text">You must accept this to proceed.</Fragment>
    </Switch>
    <Switch name="switch-spread" spread disabled>
    Disabled
    <Fragment slot="end-text">This switch is disabled.</Fragment>
    </Switch>
    <Switch name="switch-spread" spread error>
    Invalid Switch
    <Fragment slot="end-text">There is an error with this switch.</Fragment>
    </Switch>
    <label class="ui-switch ui-spread"
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-6"
    name="switch-spread"
    /><span class="ui-label">Notifications</span
    ><span id="end-text-6" class="ui-end-text"
    >Receive alerts when someone mentions you.</span
    ></label
    ><label class="ui-switch ui-spread"
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-7"
    name="switch-spread"
    required
    /><span class="ui-label">Required</span
    ><span id="end-text-7" class="ui-end-text"
    >You must accept this to proceed.</span
    ></label
    ><label class="ui-switch ui-spread"
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-8"
    name="switch-spread"
    disabled
    /><span class="ui-label">Disabled</span
    ><span id="end-text-8" class="ui-end-text"
    >This switch is disabled.</span
    ></label
    ><label class="ui-switch ui-spread" data-invalid
    ><input
    type="checkbox"
    role="switch"
    aria-describedby="end-text-9"
    name="switch-spread"
    /><span class="ui-label">Invalid Switch</span
    ><span id="end-text-9" class="ui-end-text"
    >There is an error with this switch.</span
    ></label
    >

    Sizes

    Set the small prop for a smaller Switch variant.

    ---
    import { Switch } from "@opui/astro"
    ---
    <div class="example-row">
    <Switch name="switch-sizes" small checked hideLabel>Small</Switch>
    <Switch name="switch-sizes" checked hideLabel>Default</Switch>
    </div>
    <div class="example-row">
    <Switch name="switch-sizes" small checked>Small</Switch>
    <Switch name="switch-sizes" checked>Default</Switch>
    </div>
    <div class="example-row">
    <label class="ui-switch ui-small"
    ><input type="checkbox" role="switch" name="switch-sizes" checked /><span
    class="ui-sr-only"
    >Small</span
    ></label
    ><label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-sizes" checked /><span
    class="ui-sr-only"
    >Default</span
    ></label
    >
    </div>
    <div class="example-row">
    <label class="ui-switch ui-small"
    ><input type="checkbox" role="switch" name="switch-sizes" checked /><span
    class="ui-label"
    >Small</span
    ></label
    ><label class="ui-switch"
    ><input type="checkbox" role="switch" name="switch-sizes" checked /><span
    class="ui-label"
    >Default</span
    ></label
    >
    </div>

    Icons

    ---
    import { Switch } from "@opui/astro"
    ---
    <Switch name="switch-icons" small aria-label="Toggle theme">
    <svg
    slot="icon-unchecked"
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    ><path
    fill="currentColor"
    d="M20.026 17.001c-2.762 4.784-8.879 6.423-13.663 3.661A10 10 0 0 1 3.13 17.68a.75.75 0 0 1 .365-1.132c3.767-1.348 5.785-2.91 6.956-5.146c1.233-2.353 1.551-4.93.689-8.463a.75.75 0 0 1 .769-.927a9.96 9.96 0 0 1 4.457 1.327c4.784 2.762 6.423 8.879 3.66 13.662"
    ></path></svg
    >
    <svg
    slot="icon-checked"
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    ><path
    fill="currentColor"
    d="M12 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 2m5 10a5 5 0 1 1-10 0a5 5 0 0 1 10 0m4.25.75a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zM12 19a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 19m-7.75-6.25a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zm-.03-8.53a.75.75 0 0 1 1.06 0l1.5 1.5a.75.75 0 0 1-1.06 1.06l-1.5-1.5a.75.75 0 0 1 0-1.06m1.06 15.56a.75.75 0 1 1-1.06-1.06l1.5-1.5a.75.75 0 1 1 1.06 1.06zm14.5-15.56a.75.75 0 0 0-1.06 0l-1.5 1.5a.75.75 0 0 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06m-1.06 15.56a.75.75 0 1 0 1.06-1.06l-1.5-1.5a.75.75 0 1 0-1.06 1.06z"
    ></path></svg
    >
    </Switch>
    <Switch name="switch-icons" checked aria-label="Toggle theme">
    <svg
    slot="icon-unchecked"
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    ><path
    fill="currentColor"
    d="M20.026 17.001c-2.762 4.784-8.879 6.423-13.663 3.661A10 10 0 0 1 3.13 17.68a.75.75 0 0 1 .365-1.132c3.767-1.348 5.785-2.91 6.956-5.146c1.233-2.353 1.551-4.93.689-8.463a.75.75 0 0 1 .769-.927a9.96 9.96 0 0 1 4.457 1.327c4.784 2.762 6.423 8.879 3.66 13.662"
    ></path></svg
    >
    <svg
    slot="icon-checked"
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    ><path
    fill="currentColor"
    d="M12 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 2m5 10a5 5 0 1 1-10 0a5 5 0 0 1 10 0m4.25.75a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zM12 19a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 19m-7.75-6.25a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zm-.03-8.53a.75.75 0 0 1 1.06 0l1.5 1.5a.75.75 0 0 1-1.06 1.06l-1.5-1.5a.75.75 0 0 1 0-1.06m1.06 15.56a.75.75 0 1 1-1.06-1.06l1.5-1.5a.75.75 0 1 1 1.06 1.06zm14.5-15.56a.75.75 0 0 0-1.06 0l-1.5 1.5a.75.75 0 0 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06m-1.06 15.56a.75.75 0 1 0 1.06-1.06l-1.5-1.5a.75.75 0 1 0-1.06 1.06z"
    ></path></svg
    >
    </Switch>
    <label class="ui-switch ui-small"
    ><span class="ui-icon-unchecked" aria-hidden="true"
    ><svg
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    >
    <path
    fill="currentColor"
    d="M20.026 17.001c-2.762 4.784-8.879 6.423-13.663 3.661A10 10 0 0 1 3.13 17.68a.75.75 0 0 1 .365-1.132c3.767-1.348 5.785-2.91 6.956-5.146c1.233-2.353 1.551-4.93.689-8.463a.75.75 0 0 1 .769-.927a9.96 9.96 0 0 1 4.457 1.327c4.784 2.762 6.423 8.879 3.66 13.662"
    ></path></svg></span
    ><span class="ui-icon-checked" aria-hidden="true"
    ><svg
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    >
    <path
    fill="currentColor"
    d="M12 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 2m5 10a5 5 0 1 1-10 0a5 5 0 0 1 10 0m4.25.75a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zM12 19a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 19m-7.75-6.25a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zm-.03-8.53a.75.75 0 0 1 1.06 0l1.5 1.5a.75.75 0 0 1-1.06 1.06l-1.5-1.5a.75.75 0 0 1 0-1.06m1.06 15.56a.75.75 0 1 1-1.06-1.06l1.5-1.5a.75.75 0 1 1 1.06 1.06zm14.5-15.56a.75.75 0 0 0-1.06 0l-1.5 1.5a.75.75 0 0 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06m-1.06 15.56a.75.75 0 1 0 1.06-1.06l-1.5-1.5a.75.75 0 1 0-1.06 1.06z"
    ></path></svg></span
    ><input
    type="checkbox"
    role="switch"
    name="switch-icons"
    aria-label="Toggle theme" /></label
    ><label class="ui-switch"
    ><span class="ui-icon-unchecked" aria-hidden="true"
    ><svg
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    >
    <path
    fill="currentColor"
    d="M20.026 17.001c-2.762 4.784-8.879 6.423-13.663 3.661A10 10 0 0 1 3.13 17.68a.75.75 0 0 1 .365-1.132c3.767-1.348 5.785-2.91 6.956-5.146c1.233-2.353 1.551-4.93.689-8.463a.75.75 0 0 1 .769-.927a9.96 9.96 0 0 1 4.457 1.327c4.784 2.762 6.423 8.879 3.66 13.662"
    ></path></svg></span
    ><span class="ui-icon-checked" aria-hidden="true"
    ><svg
    xmlns="http://www.w3.org/2000/svg"
    width="24"
    height="24"
    viewBox="0 0 24 24"
    >
    <path
    fill="currentColor"
    d="M12 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 2m5 10a5 5 0 1 1-10 0a5 5 0 0 1 10 0m4.25.75a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zM12 19a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 19m-7.75-6.25a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5zm-.03-8.53a.75.75 0 0 1 1.06 0l1.5 1.5a.75.75 0 0 1-1.06 1.06l-1.5-1.5a.75.75 0 0 1 0-1.06m1.06 15.56a.75.75 0 1 1-1.06-1.06l1.5-1.5a.75.75 0 1 1 1.06 1.06zm14.5-15.56a.75.75 0 0 0-1.06 0l-1.5 1.5a.75.75 0 0 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06m-1.06 15.56a.75.75 0 1 0 1.06-1.06l-1.5-1.5a.75.75 0 1 0-1.06 1.06z"
    ></path></svg></span
    ><input
    type="checkbox"
    role="switch"
    name="switch-icons"
    checked
    aria-label="Toggle theme"
    /></label>

    Field group

    Use field groups to group related switches.

    The name prop will get passed down to each switch in the group.

    See also: Form documentation.

    Legend
    ---
    import { Switch } from "@opui/astro"
    import { FieldSet } from "@opui/astro"
    import { FieldLegend } from "@opui/astro"
    import { FieldGroup } from "@opui/astro"
    import { Form } from "@opui/astro"
    ---
    <Form as="div">
    <FieldSet>
    <FieldLegend>Legend</FieldLegend>
    <FieldGroup name="switch-group">
    <Switch>Switch 1</Switch>
    <Switch>Switch 2</Switch>
    <Switch>Switch 3</Switch>
    </FieldGroup>
    </FieldSet>
    </Form>
    <div class="ui-form">
    <fieldset class="ui-fieldset">
    <legend>Legend</legend>
    <div class="ui-field-group" role="group">
    <label class="ui-switch"
    ><input name="switch-group" type="checkbox" role="switch" /><span
    class="ui-label"
    >Switch 1</span
    ></label
    ><label class="ui-switch"
    ><input name="switch-group" type="checkbox" role="switch" /><span
    class="ui-label"
    >Switch 2</span
    ></label
    ><label class="ui-switch"
    ><input name="switch-group" type="checkbox" role="switch" /><span
    class="ui-label"
    >Switch 3</span
    ></label
    >
    </div>
    </fieldset>
    </div>

    Direction

    Legend
    ---
    import { Switch } from "@opui/astro"
    import { FieldSet } from "@opui/astro"
    import { FieldLegend } from "@opui/astro"
    import { FieldGroup } from "@opui/astro"
    import { Form } from "@opui/astro"
    ---
    <Form>
    <FieldSet>
    <FieldLegend>Legend</FieldLegend>
    <FieldGroup direction="row" name="switch-group-direction">
    <Switch>Switch 1</Switch>
    <Switch>Switch 2</Switch>
    <Switch>Switch 3</Switch>
    </FieldGroup>
    </FieldSet>
    </Form>
    <form class="ui-form">
    <fieldset class="ui-fieldset">
    <legend>Legend</legend>
    <div class="ui-field-group ui-row" role="group">
    <label class="ui-switch"
    ><input
    name="switch-group-direction"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 1</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-direction"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 2</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-direction"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 3</span></label
    >
    </div>
    </fieldset>
    </form>

    Field description

    Can be placed above and below the fields.

    Legend

    Field description above fields

    Legend

    Field description below fields

    ---
    import { Switch } from "@opui/astro"
    import { FieldSet } from "@opui/astro"
    import { FieldLegend } from "@opui/astro"
    import { FieldDescription } from "@opui/astro"
    import { FieldGroup } from "@opui/astro"
    import { Form } from "@opui/astro"
    ---
    <Form>
    <FieldSet>
    <FieldLegend>Legend</FieldLegend>
    <FieldDescription>Field description above fields</FieldDescription>
    <FieldGroup direction="row" name="switch-group-field-description-1">
    <Switch>Switch 1</Switch>
    <Switch>Switch 2</Switch>
    <Switch>Switch 3</Switch>
    </FieldGroup>
    </FieldSet>
    <FieldSet>
    <FieldLegend>Legend</FieldLegend>
    <FieldGroup direction="row" name="switch-group-field-description-2">
    <Switch>Switch 1</Switch>
    <Switch>Switch 2</Switch>
    <Switch>Switch 3</Switch>
    </FieldGroup>
    <FieldDescription>Field description below fields</FieldDescription>
    </FieldSet>
    </Form>
    <form class="ui-form">
    <fieldset class="ui-fieldset">
    <legend>Legend</legend>
    <p class="ui-field-description">Field description above fields</p>
    <div class="ui-field-group ui-row" role="group">
    <label class="ui-switch"
    ><input
    name="switch-group-field-description-1"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 1</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-field-description-1"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 2</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-field-description-1"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 3</span></label
    >
    </div>
    </fieldset>
    <fieldset class="ui-fieldset">
    <legend>Legend</legend>
    <div class="ui-field-group ui-row" role="group">
    <label class="ui-switch"
    ><input
    name="switch-group-field-description-2"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 1</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-field-description-2"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 2</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-field-description-2"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 3</span></label
    >
    </div>
    <p class="ui-field-description">Field description below fields</p>
    </fieldset>
    </form>

    Disabled

    Attach the disabled attribute to the <fieldset> element.

    Legend
    ---
    import { Switch } from "@opui/astro"
    import { FieldSet } from "@opui/astro"
    import { FieldLegend } from "@opui/astro"
    import { FieldGroup } from "@opui/astro"
    import { Form } from "@opui/astro"
    ---
    <Form>
    <FieldSet disabled>
    <FieldLegend>Legend</FieldLegend>
    <FieldGroup direction="row" name="switch-group-disabled">
    <Switch>Switch 1</Switch>
    <Switch>Switch 2</Switch>
    <Switch>Switch 3</Switch>
    </FieldGroup>
    </FieldSet>
    </Form>
    <form class="ui-form">
    <fieldset disabled class="ui-fieldset">
    <legend>Legend</legend>
    <div class="ui-field-group ui-row" role="group">
    <label class="ui-switch"
    ><input
    name="switch-group-disabled"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 1</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-disabled"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 2</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-disabled"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 3</span></label
    >
    </div>
    </fieldset>
    </form>

    Required

    Attach the required attribute to at least one of your <input> elements.

    These are required!
    ---
    import { Switch } from "@opui/astro"
    import { FieldSet } from "@opui/astro"
    import { FieldLegend } from "@opui/astro"
    import { FieldGroup } from "@opui/astro"
    import { Form } from "@opui/astro"
    ---
    <Form>
    <FieldSet>
    <FieldLegend>These are required!</FieldLegend>
    <FieldGroup direction="row" name="switch-group-required">
    <Switch required>Switch 1</Switch>
    <Switch required>Switch 2</Switch>
    <Switch required>Switch 3</Switch>
    </FieldGroup>
    </FieldSet>
    </Form>
    <form class="ui-form">
    <fieldset class="ui-fieldset">
    <legend>These are required!</legend>
    <div class="ui-field-group ui-row" role="group">
    <label class="ui-switch"
    ><input
    name="switch-group-required"
    type="checkbox"
    role="switch"
    required
    /><span class="ui-label">Switch 1</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-required"
    type="checkbox"
    role="switch"
    required
    /><span class="ui-label">Switch 2</span></label
    ><label class="ui-switch"
    ><input
    name="switch-group-required"
    type="checkbox"
    role="switch"
    required
    /><span class="ui-label">Switch 3</span></label
    >
    </div>
    </fieldset>
    </form>

    Validation

    Attach the data-invalid attribute to your Fieldset component.

    Legend
    Something went wrong!
    ---
    import { Switch } from "@opui/astro"
    import { FieldSet } from "@opui/astro"
    import { FieldLegend } from "@opui/astro"
    import { FieldGroup } from "@opui/astro"
    import { Form } from "@opui/astro"
    ---
    <Form>
    <FieldSet data-invalid="">
    <FieldLegend>Legend</FieldLegend>
    <FieldGroup direction="row" name="switch-field-group-validation">
    <Switch>Switch 1</Switch>
    <Switch>Switch 2</Switch>
    <Switch>Switch 3</Switch>
    </FieldGroup>
    <span class="ui-end-text">Something went wrong!</span>
    </FieldSet>
    </Form>
    <form class="ui-form">
    <fieldset data-invalid class="ui-fieldset">
    <legend>Legend</legend>
    <div class="ui-field-group ui-row" role="group">
    <label class="ui-switch"
    ><input
    name="switch-field-group-validation"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 1</span></label
    ><label class="ui-switch"
    ><input
    name="switch-field-group-validation"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 2</span></label
    ><label class="ui-switch"
    ><input
    name="switch-field-group-validation"
    type="checkbox"
    role="switch"
    /><span class="ui-label">Switch 3</span></label
    >
    </div>
    <span class="ui-end-text">Something went wrong!</span>
    </fieldset>
    </form>

    Accessibility

    Role & attributes

    Role/attributeUsage
    role="switch"Required on the input element. Identifies the element that serves as a switch.

    Labels

    Accessible switches should have a label. The first two approaches are equally ok:

    ApproachUsage in Switch component
    Provide a label inside the elementUse a .ui-label child for a visible label, or a .ui-sr-only child to hide it visually while keeping it accessible. In Astro, set the hideLabel prop to render the slot content as .ui-sr-only.
    Add an aria-label on the inputUsed when there's no visible label inside the component (e.g. icon-only switches). In Astro, pass aria-label as a prop on the component and it will land on the input.
    Have a visible label that you reference with aria-labelledbyNot used.

    Keyboard support

    KeyFunction
    SpaceWhen Switch is focused it changes its state.
    Enter(Optional) When Switch is focused it changes its state.

    API

    Switch API

    PropTypeDefaultDescription
    errorbooleanfalseShows error styles.
    hideLabelbooleanfalseVisually hides the label.
    smallbooleanfalseThe size of the element.
    spreadbooleanfalsePushes the label and the switch to opposite ends.
    stackbooleanfalseStacks the label under the switch.

    Slots

    SlotDescription
    defaultThe label.
    end-textSupporting text displayed below the label.
    icon-checkedAn optional icon in the thumb when checked.
    icon-uncheckedAn optional icon in the thumb when unchecked.

    Other attributes, such as checked, disabled, name and required, go to the <input>. Without a label, set aria-label or aria-labelledby.

    Field group API

    PropTypeDefaultDescription
    direction"row", "column"-The orientation of the element.
    namestring-Sets name on every input, select and textarea inside.

    Slots

    SlotDescription
    defaultThe fields, such as checkboxes, radios or switches.

    Browser support

    Full supportSupported since v123.Full supportSupported since v121.Full supportSupported since v17.5.

    See also the full browser support guide.

    Installation

    See also

    @layer components.root {
    :where(.ui-switch) {
    --_motion: var(--motion, 1);
    --_accent-color: var(--primary);
    --_accent-contrast: var(--primary-contrast);
    --_dot-bg-color: light-dark(var(--gray-11), var(--gray-14));
    --_dot-inset: var(--size-1) auto auto var(--size-1);
    --_dot-outline-size: 0;
    --_dot-size: var(--size-3);
    --_track-bg-color: light-dark(var(--gray-3), var(--gray-8));
    --_track-height: var(--size-5);
    --_track-width: var(--size-8);
    --_transition-tf: var(--ease-4);
    --_transition-time: calc(0.2s * var(--_motion));
    align-items: center;
    color: var(--text-primary);
    display: inline-grid;
    gap: 0 var(--size-2);
    grid-auto-columns: auto;
    grid-auto-flow: column;
    inline-size: fit-content;
    :where(input[type="checkbox"][role="switch"]) {
    appearance: none;
    block-size: var(--_track-height);
    cursor: pointer;
    inline-size: var(--_track-width);
    margin: 0;
    position: relative;
    /* Track */
    &::before {
    background-color: var(--_track-bg-color);
    block-size: var(--_track-height);
    border: 1px solid var(--_dot-bg-color);
    border-radius: var(--radius-round);
    content: "";
    inline-size: var(--_track-width);
    inset: 0;
    position: absolute;
    }
    &:focus-visible {
    --focus-ring-color: currentColor;
    outline: var(--focus-ring-width) var(--focus-ring-style)
    var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
    }
    /* Dot */
    &::after {
    background-color: var(--_dot-bg-color);
    block-size: var(--_dot-size);
    border-radius: var(--radius-round);
    content: "";
    inline-size: var(--_dot-size);
    inset: var(--_dot-inset);
    outline: var(--_dot-outline-size) solid var(--_dot-bg-color);
    outline-offset: -1px;
    position: absolute;
    }
    /* Checked */
    &:checked {
    &::before {
    background-color: var(--_accent-color);
    border-color: var(--_accent-color);
    transition:
    background-color var(--_transition-time) var(--_transition-tf),
    border-color var(--_transition-time) var(--_transition-tf);
    }
    /* Dot */
    &::after {
    --_dot-bg-color: var(--_accent-contrast);
    --_dot-outline-size: calc(var(--size-1) - 1px);
    inset-inline-start: calc(
    var(--_track-width) - var(--_dot-size) - var(--size-1)
    );
    }
    }
    /* Animation */
    /* Track */
    &::before {
    transition:
    background-color var(--_transition-time) var(--_transition-tf),
    border-color var(--_transition-time) var(--_transition-tf);
    }
    /* Dot */
    &::after {
    transition: all var(--_transition-time) var(--_transition-tf);
    }
    &:active:after {
    --_dot-outline-size: calc(var(--size-1) + 1px);
    }
    &:checked {
    &:active:after {
    --_dot-outline-size: calc(var(--size-1) + 1px);
    }
    }
    }
    /* Icons */
    &:has(.ui-icon-checked, .ui-icon-unchecked) {
    [role="switch"] {
    grid-column: 1 / -1;
    grid-row: 1;
    }
    &:has([role="switch"]:checked) {
    .ui-icon-unchecked {
    display: none;
    }
    .ui-icon-checked {
    display: block;
    }
    }
    .ui-icon-checked {
    display: none;
    }
    .ui-icon-unchecked,
    .ui-icon-checked {
    grid-column: 1;
    grid-row: 1;
    pointer-events: none;
    z-index: 1;
    svg {
    display: block;
    inline-size: var(--_dot-size);
    }
    }
    .ui-icon-unchecked {
    margin-inline-start: calc(
    var(--_track-width) - var(--_dot-size) - var(--size-1)
    );
    }
    .ui-icon-checked {
    margin-inline-start: var(--size-1);
    }
    }
    /* Required dot */
    &:has(:invalid) {
    .ui-label:after {
    color: var(--red);
    content: "*";
    inset: 0 -0.25ex auto auto;
    position: absolute;
    }
    }
    /* Disabled */
    &:has([disabled]) {
    cursor: not-allowed;
    opacity: 0.64;
    user-select: none;
    input {
    cursor: not-allowed;
    }
    }
    /* Label */
    .ui-label {
    color: var(--text-primary);
    font-size: var(--font-size-05);
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    padding-inline: 0 1ex;
    position: relative;
    user-select: none;
    }
    /* End text */
    :where(.ui-end-text) {
    color: var(--text-muted);
    font-size: var(--font-size-0);
    grid-column: 2;
    grid-row: 2;
    line-height: 1.5;
    z-index: 1;
    }
    /* Size */
    &.ui-small {
    --_dot-size: 0.75rem;
    --_track-height: var(--size-4);
    --_track-width: 2.5rem;
    }
    /* Spread layout */
    &.ui-spread {
    align-items: center;
    column-gap: var(--size-4);
    grid-auto-flow: unset;
    grid-template-columns: 1fr auto;
    inline-size: 100%;
    .ui-label {
    font-weight: 600;
    grid-column: 1;
    grid-row: 1;
    inline-size: fit-content;
    }
    input[role="switch"] {
    grid-column: 2;
    grid-row: 1;
    }
    &:has(.ui-icon-checked, .ui-icon-unchecked) {
    input[role="switch"],
    .ui-icon-checked,
    .ui-icon-unchecked {
    grid-column: 2;
    }
    }
    :where(.ui-end-text) {
    grid-column: 1;
    grid-row: 2;
    }
    }
    /* Stacked layout */
    &.ui-stack {
    grid-auto-columns: unset;
    justify-items: center;
    .ui-label {
    grid-column: 1/-1;
    grid-row: 2;
    margin-block-start: var(--size-1);
    padding-inline: 1ex;
    }
    .ui-end-text {
    grid-column: 1/-1;
    grid-row: 3;
    }
    }
    /* Validation */
    &[data-invalid] {
    input {
    border-radius: var(--radius-round);
    outline: 2px solid var(--color-9);
    }
    .ui-end-text {
    color: var(--color-9);
    }
    }
    }
    }
    @layer components.extended {
    /* Form */
    :where(.ui-form) {
    display: grid;
    gap: var(--size-8);
    hr {
    margin-block: 0;
    }
    }
    /* Fieldset */
    :where(.ui-fieldset) {
    all: unset;
    border: 0;
    border-radius: 0;
    display: grid;
    gap: var(--size-1);
    margin: 0;
    min-inline-size: 0;
    padding: 0;
    /* Legend */
    :where(legend, .ui-legend) {
    all: unset;
    color: var(--text-primary);
    font-weight: 600;
    margin-block-end: var(--size-3);
    padding: 0;
    &:has(+ :where(.ui-field-description)) {
    margin-block-end: 0;
    }
    }
    /* Field description / supporting text */
    :where(.ui-field-description) {
    color: var(--text-muted);
    font-size: var(--font-size-05);
    line-height: var(--font-lineheight-3);
    &:has(+ *) {
    margin-block-end: var(--size-3);
    }
    }
    /* End text */
    :where(.ui-end-text) {
    color: var(--text-muted);
    font-size: var(--font-size-0);
    line-height: var(--font-lineheight-3);
    }
    &:has(.ui-text-field.ui-row) {
    row-gap: var(--size-7);
    }
    /* Disabled */
    &[disabled] {
    opacity: 0.64;
    user-select: none;
    input,
    label,
    .ui-label {
    cursor: not-allowed;
    }
    }
    /* Error / validation */
    &[data-invalid] {
    :where(.ui-end-text) {
    color: var(--critical);
    }
    :where(.ui-checkbox, .ui-radio, .ui-switch) {
    --primary: var(--critical);
    :where(.ui-end-text) {
    color: var(--critical);
    }
    }
    :where(.ui-switch) {
    input {
    border-radius: var(--radius-round);
    outline: 2px solid var(--critical);
    }
    }
    }
    /* Required */
    &:has(:invalid) {
    :where(legend, .ui-legend) {
    padding-inline-end: 1ex;
    position: relative;
    &::after {
    color: var(--red);
    content: "*";
    inset: 0 -0.25ex auto auto;
    position: absolute;
    }
    }
    }
    }
    /* Field group */
    :where(.ui-field-group) {
    display: flex;
    flex-direction: column;
    gap: var(--size-4);
    /* If it only has checkboxes, radios, or switches */
    &:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)):not(
    :has(> :not(.ui-checkbox, .ui-radio, .ui-switch))
    ) {
    gap: var(--size-2);
    }
    /* If it only has buttons */
    &:has(.ui-button):not(:has(*:not(.ui-button))) {
    align-items: center;
    flex-direction: row;
    gap: var(--size-2);
    /* If it's not preceded by an hr */
    &:not(hr + &) {
    margin-block-start: var(--size-4);
    }
    }
    & + & {
    margin-block-start: var(--size-5);
    }
    /* Directions */
    &.ui-row {
    flex-direction: row;
    flex-wrap: wrap;
    &:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)) {
    gap: var(--size-4);
    }
    }
    }
    }