UISwitch
UISwitch
A versatile switch component that provides a sliding toggle interface for boolean values, with support for custom styling, labels, and loading states.
<template> <UISwitch v-model="enabled" :size="'md'" :disabled="false" :loading="false" @change="handleChange" > <template #label> Enable notifications </template> </UISwitch></template>
<script setup lang="ts">const enabled = ref(false)
const handleChange = (value: boolean) => { console.log('Switch toggled:', value)}</script>Props
modelValue(boolean): Current statesize(string): Switch size (‘sm’ | ‘md’ | ‘lg’)disabled(boolean): Disable switchloading(boolean): Show loading statecolor(string): Active colorname(string): Input namerequired(boolean): Mark as requirederror(boolean): Show error statelabel(string): Switch labellabelPosition(string): Label position
Events
update:modelValue: State updatedchange: Value changedfocus: Switch focusedblur: Switch blurred
Slots
label: Custom label contenticon: Custom icon contentloading: Custom loading state
Usage Examples
- Basic Switch:
<template> <UISwitch v-model="darkMode"> Dark Mode </UISwitch></template>
<script setup>const darkMode = ref(false)</script>- Switch with Custom Styling:
<template> <UISwitch v-model="status" class="custom-switch" > <template #label> <div class="flex items-center space-x-2"> <StatusIcon :class="[ 'w-4 h-4', status ? 'text-success-500' : 'text-gray-400' ]" /> <span>{{ status ? 'Active' : 'Inactive' }}</span> </div> </template> </UISwitch></template>
<script setup>const status = ref(false)</script>
<style>.custom-switch { --switch-color: theme('colors.success.500'); --switch-bg: theme('colors.success.100');}</style>- Form Integration:
<template> <form @submit.prevent="handleSubmit"> <div class="space-y-4"> <div class="space-y-2"> <label class="text-sm font-medium"> Preferences </label>
<div class="space-y-3"> <UISwitch v-model="preferences.emails" name="email_notifications" > Email notifications </UISwitch>
<UISwitch v-model="preferences.updates" name="product_updates" > Product updates </UISwitch>
<UISwitch v-model="preferences.newsletter" name="newsletter" > Weekly newsletter </UISwitch> </div> </div>
<UIButton type="submit"> Save Preferences </UIButton> </div> </form></template>
<script setup>const preferences = reactive({ emails: false, updates: true, newsletter: false})
const handleSubmit = () => { // Handle form submission}</script>Best Practices
-
Visual Design:
- Clear states
- Smooth animation
- Consistent sizing
- Proper spacing
-
User Experience:
- Immediate feedback
- Clear labeling
- Touch targets
- Loading states
-
Accessibility:
- ARIA labels
- Keyboard support
- Focus states
- Screen reader support
-
Implementation:
- State management
- Form integration
- Error handling
- Loading feedback
Common Use Cases
- Feature Toggle:
<template> <div class="space-y-4"> <h3 class="text-lg font-medium"> Feature Settings </h3>
<div class="space-y-3"> <div v-for="feature in features" :key="feature.id" class="flex items-center justify-between p-4 bg-gray-50 rounded-lg" > <div> <div class="font-medium"> {{ feature.name }} </div> <div class="text-sm text-gray-500"> {{ feature.description }} </div> </div>
<UISwitch v-model="feature.enabled" :loading="feature.loading" @change="toggleFeature(feature)" /> </div> </div> </div></template>
<script setup>const features = ref([ { id: 1, name: 'Beta Features', description: 'Access to upcoming features', enabled: false, loading: false }, // ... more features])
const toggleFeature = async (feature) => { feature.loading = true try { await updateFeatureStatus(feature) } finally { feature.loading = false }}</script>- Settings Panel:
<template> <div class="settings-panel"> <div class="space-y-6"> <section> <h4 class="text-sm font-medium text-gray-500 uppercase"> Appearance </h4>
<div class="mt-3 space-y-3"> <UISwitch v-model="settings.darkMode" @change="updateTheme" > Dark Mode </UISwitch>
<UISwitch v-model="settings.reducedMotion" @change="updateAccessibility" > Reduced Motion </UISwitch> </div> </section>
<section> <h4 class="text-sm font-medium text-gray-500 uppercase"> Privacy </h4>
<div class="mt-3 space-y-3"> <UISwitch v-model="settings.tracking" @change="updatePrivacy" > <template #label> <div> <div>Usage Analytics</div> <div class="text-sm text-gray-500"> Help us improve by sharing usage data </div> </div> </template> </UISwitch> </div> </section> </div> </div></template>- Quick Actions:
<template> <div class="quick-actions"> <div class="flex items-center justify-between p-4 border-b"> <div class="flex items-center space-x-3"> <WifiIcon class="w-5 h-5 text-gray-500" /> <span>Wi-Fi</span> </div>
<UISwitch v-model="wifi.enabled" :loading="wifi.connecting" @change="toggleWifi" /> </div>
<div class="flex items-center justify-between p-4 border-b"> <div class="flex items-center space-x-3"> <BluetoothIcon class="w-5 h-5 text-gray-500" /> <span>Bluetooth</span> </div>
<UISwitch v-model="bluetooth.enabled" :loading="bluetooth.scanning" @change="toggleBluetooth" /> </div>
<div class="flex items-center justify-between p-4"> <div class="flex items-center space-x-3"> <AirplaneModeIcon class="w-5 h-5 text-gray-500" /> <span>Airplane Mode</span> </div>
<UISwitch v-model="airplaneMode" @change="toggleAirplaneMode" /> </div> </div></template>
<script setup>const wifi = reactive({ enabled: true, connecting: false})
const bluetooth = reactive({ enabled: false, scanning: false})
const airplaneMode = ref(false)
const toggleWifi = async () => { wifi.connecting = true try { await updateWifiStatus(wifi.enabled) } finally { wifi.connecting = false }}
const toggleBluetooth = async () => { bluetooth.scanning = true try { await updateBluetoothStatus(bluetooth.enabled) } finally { bluetooth.scanning = false }}
const toggleAirplaneMode = () => { if (airplaneMode.value) { wifi.enabled = false bluetooth.enabled = false }}</script>