Skip to content

Switch

An on-off switch for a setting that applies as soon as it is flipped.

View source View as Markdown

Switch is a two-state control for a setting the user turns on and off. Useful wherever the change should apply the moment it is made; for a choice that only counts once a form is submitted, use Checkbox.

App.vue
<template>
  <div class="flex flex-col gap-3">
    <Field.Root
      v-for="setting in settings"
      :key="setting.name"
      class="flex items-center gap-3 data-[disabled=true]:cursor-not-allowed"
      :options="{ disabled: setting.disabled, name: setting.name }"
    >
      <Switch.Root v-model="setting.enabled" :class="track">
        <Switch.Thumb :class="thumb" />
      </Switch.Root>

      <Field.Label :class="label">{{ setting.label }}</Field.Label>
    </Field.Root>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { Field } from '@maas/mirror/vue/Field'
import { Switch } from '@maas/mirror/vue/Switch'

const track = [
  'group/switch flex h-6 w-[2.625rem] items-center p-[0.0625rem]',
  'rounded-component-round border-2 border-[transparent] bg-primary-subtle',
  'transition-all duration-100 ease-[ease]',
  'data-[disabled=true]:pointer-events-none',
  'outline-4 outline-transparent focus-visible:focus-ring',
  'not-data-[disabled=true]:active:bg-primary-subtle-active',
  'data-[state=checked]:bg-accent-solid',
  'not-data-[disabled=true]:data-[state=checked]:active:bg-accent-solid-active',
  'data-[disabled=true]:bg-disabled-muted',
].join(' ')

const thumb = [
  'rounded-component-round bg-primary-light block size-[1.125rem]',
  'shadow-[0_0.0625rem_0.125rem_0_oklch(0%_0_none/0.24)]',
  'transition-all duration-100 ease-[ease]',
  'data-[state=checked]:translate-x-[1.125rem]',
  'not-data-[disabled=true]:group-active/switch:w-[1.375rem]',
  'not-data-[disabled=true]:group-active/switch:data-[state=checked]:translate-x-[0.875rem]',
  'data-[disabled=true]:bg-disabled-light',
].join(' ')

const label = [
  'type-component-xs text-surface [--mirror-label-cursor:pointer]',
  'data-[disabled=true]:text-disabled-solid',
].join(' ')

const settings = ref([
  {
    name: 'notifications',
    label: 'Email notifications',
    enabled: true,
    disabled: false,
  },
  { name: 'digest', label: 'Weekly digest', enabled: false, disabled: false },
  { name: 'beta', label: 'Beta features', enabled: false, disabled: true },
])
</script>

Usage guidelines

  • Make sure the switch has an accessible name, either through a Label inside a Field or an aria-label on the root.must
  • readOnly never reaches the hidden input, so a read-only switch still submits its value. Use disabled to leave it out of the submission.should