Skip to content

SwitchField

SwitchField component for on/off toggle actions. Compliant with W3C standards with complete accessibility support and intelligent label positioning.

Usage examples

Basic Switch

Simple switch

vue
<script setup>
const notifications = ref(false)
</script>

<template>
  <SuSwitchField
    label="Notifications"
    message="Enable push notifications"
    v-model="notifications"
  />
</template>

Switch with side labels

With single label (aligned beside)

vue
<template>
  <SuSwitchField
    label="Dark mode"
    rightLabel="Enabled"
    message="Switch to dark theme"
    v-model="darkMode"
  />
</template>

Switch with labels on both sides

With left and right labels (centered)

vue
<template>
  <SuSwitchField
    label="Profile visibility"
    leftLabel="Private"
    rightLabel="Public"
    message="Control who can see your profile"
    v-model="isPublic"
  />
</template>

Sizes

Available sizes

vue
<template>
  <SuSwitchFieldsize="sm" label="Small" rightLabel="Small" />
  <SuSwitchFieldsize="md" label="Medium" rightLabel="Medium" />
  <SuSwitchFieldsize="lg" label="Large" rightLabel="Large" />
</template>

States and validation

Validation states

vue
<template>
  <SuSwitchField
    state="default"
    label="Default state"
    message="Normal operation"
  />
  <SuSwitchField
    state="error"
    label="Error state"
    message="An error occurred"
  />
  <SuSwitchField
    state="success"
    label="Success state"
    message="Configuration saved!"
  />
  <SuSwitchField
    state="warning"
    label="Warning state"
    message="This action requires confirmation"
  />
</template>

API

Props

PropTypeDefaultDescription
valuebooleanfalseSwitch state (on/off)
size'sm' | 'md' | 'lg''md'Switch size
state'default' | 'error' | 'success' | 'warning''default'Switch visual state
disabledbooleanfalseDisable the switch
readonlybooleanfalseRead-only switch
requiredbooleanfalseRequired field
labelstringundefinedMain switch label
leftLabelstringundefinedLabel displayed to the left of switch
rightLabelstringundefinedLabel displayed to the right of switch
messagestringundefinedDisplayed message

Events

EventTypeDescription
@update:modelValue(value: boolean) => voidEmitted when state changes (v-model)
@change(value: boolean) => voidEmitted on change
@focus(event: FocusEvent) => voidEmitted on focus
@blur(event: FocusEvent) => voidEmitted on blur
@keydown(event: KeyboardEvent) => voidEmitted on key press

Label positioning

The Switch component automatically adapts positioning based on provided labels:

🎯 Positioning logic

  • No side label: Switch aligned to the left
  • Single label (leftLabel OR rightLabel): Switch aligned next to label
  • Two labels (leftLabel AND rightLabel): Switch centered between labels
vue
<!-- Switch to the left -->
<SuSwitchFieldlabel="Notifications" />

<!-- Switch next to label -->
<SuSwitchFieldlabel="Dark mode" rightLabel="Enabled" />

<!-- Switch centered -->
<SuSwitchFieldlabel="Visibility" leftLabel="Private" rightLabel="Public" />

Accessibility

The Switch component follows WCAG 2.1 AA standards and W3C best practices:

✅ Accessibility features

  • ARIA role: role="switch" with aria-checked
  • Keyboard navigation: Support for Space and Enter keys
  • Associated labels: Each switch has a properly associated label
  • State messages: Messages with aria-live for screen readers
  • Color contrast: WCAG AA compliant contrast ratios (4.5:1 minimum)
  • Visible focus: Clear and contrasted focus indicator
  • Minimum sizes: Respects minimum touch target sizes (44px)
  • Dark mode: Automatically adapted contrast
  • High contrast: Support for prefers-contrast: high
  • Reduced motion: Respects prefers-reduced-motion

🎯 Best practices

vue
<!-- Switch with complete accessibility -->
<SuSwitchField
  label="Push notifications"
  rightLabel="Enabled"
  :required="true"
  message="Receive real-time notifications"
  ariaLabel="Enable push notifications"
  v-model="pushNotifications"
/>

<!-- Switch with error handling -->
<SuSwitchField
  label="Synchronization"
  leftLabel="Disabled"
  rightLabel="Enabled"
  :state="hasError ? 'error' : 'default'"
  :message="hasError ? 'Synchronization error' : 'Automatic data synchronization'"
  v-model="syncEnabled"
/>

<!-- Switch with validation -->
<SuSwitchField
  label="Accept terms"
  rightLabel="I accept"
  :required="true"
  :state="!termsAccepted ? 'error' : 'success'"
  :message="!termsAccepted ? 'You must accept the terms' : 'Terms accepted'"
  v-model="termsAccepted"
/>

Keyboard navigation

KeyAction
TabNavigate to/from switch
SpaceToggle switch state
EnterToggle switch state

Advanced usage examples

Settings panel

vue
<script setup>
import { ref } from 'vue'

const settings = ref({
  notifications: true,
  darkMode: false,
  autoSave: true,
  publicProfile: false,
  emailUpdates: true
})
</script>

<template>
  <div class="settings-panel">
    <h2>Settings</h2>
    
    <div class="settings-group">
      <h3>Interface</h3>
      <SuSwitchField
        label="Dark mode"
        leftLabel="Light"
        rightLabel="Dark"
        message="Switch between light and dark themes"
        v-model="settings.darkMode"
      />
      <SuSwitchField
        label="Auto save"
        rightLabel="Enabled"
        message="Automatically save your changes"
        v-model="settings.autoSave"
      />
    </div>
    
    <div class="settings-group">
      <h3>Privacy</h3>
      <SuSwitchField
        label="Public profile"
        leftLabel="Private"
        rightLabel="Public"
        message="Control your profile visibility"
        v-model="settings.publicProfile"
      />
    </div>
    
    <div class="settings-group">
      <h3>Notifications</h3>
      <SuSwitchField
        label="Push notifications"
        rightLabel="Enabled"
        message="Receive real-time notifications"
        v-model="settings.notifications"
      />
      <SuSwitchField
        label="Email updates"
        rightLabel="Enabled"
        message="Receive news by email"
        v-model="settings.emailUpdates"
      />
    </div>
  </div>
</template>

<style scoped>
.settings-panel {
  max-width: 500px;
  margin: 0 auto;
}

.settings-group {
  margin-bottom: 2rem;
}

.settings-group h3 {
  margin-bottom: 1rem;
  color: #374151;
  font-weight: 600;
}

.settings-group > * + * {
  margin-top: 1rem;
}
</style>

Publié sous licence MIT.