๐ข Switch
Basic
use NSwitch
to create a switch input.
Label
You can use the
NFormGroup
component to create a label for the switch.
NFormGroup
component here.Outset
By default, the switch is in inset mode. You can change it to outset mode using the
outset
prop.
outset
- force the switch to be outset mode.
Color
switch="{color}"
- change the color of the switch.
primary
. You can also add your own colors to the palette through the Configuration section.Focus
switch="focus"
- add a focus color to the switch.
Size
size="{size}"
- change the size of the switch.
๐ You can freely adjust the size of the switch using any size imaginable. No limits exist, and you can use
breakpoints
such assm:sm, xs:lg
to change size based on screen size orstates
such ashover:lg, focus:3xl
to change size based on input state and more.
height
and width
of the switch scale depends on the switch-size
. If you want to change the height
and width
simultaneously, you can always customize it using utility classes.Icon
icon
- add an icon to the switch.
Disabled
disabled
- disable the switch.
Loading
loading
- set the switch to loading state.
Customization
You can customize the switch using the
una
prop and utility classes.
Slots
You can use the following slots to customize the switch.
Name | Description | Props |
---|---|---|
icon | The on and off icons of the switch. | on |
loading-icon | The loading icon slot. | on |
Props
export interface NSwitchProps {
/**
* Value of the switch.
*
* @default null
*/
modelValue?: boolean
/**
* Disable the switch from being clicked.
*
* @default false
*/
disabled?: boolean
/**
* Add a loading indicator to the switch.
* This will also disable the switch.
*
* @default false
*/
loading?: boolean
/**
* Display the slider thumb outside of the track.
*
* @default false
*/
outset?: boolean
/**
* Allows you to add `UnaUI` switch preset properties,
* Think of it as a shortcut for adding options or variants to the preset if available.
*
* @example
* switch="xl green focus"
*/
switch?: string
/**
* Allows you to display an icon when the switch is on.
* Accepts icon name and utility classes
*
* @example
* icon="i-heroicons-check-20-solid text-white"
*/
onIcon?: string
/**
* Allows you to display an icon when the switch is off.
* Accepts icon name and utility classes
*
* @example
* icon="i-heroicons-x-mark-20-solid text-white"
*/
offIcon?: string
/**
* `UnaUI` preset configuration
*
* @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/switch.ts
*/
una?: {
switchThumb?: string
switchThumbOn?: string
switchThumbOff?: string
switchTrack?: string
switchTrackOn?: string
switchTrackOff?: string
switchIconBase?: string
switchIconOn?: string
switchIconOff?: string
switchLoading?: string
switchloadingicon?: string
}
}
Presets
import type { RuleContext } from '@unocss/core'
import type { Theme } from '@unocss/preset-uno'
import { parseColor } from '@unocss/preset-mini/utils'
type SwitchPrefix = 'switch'
export const staticSwitch: Record<`${SwitchPrefix}-${string}` | SwitchPrefix, string> = {
// base
'switch': 'switch-primary bg-transparent relative inline-flex items-center justify-center flex-shrink-0 cursor-pointer rounded-full',
'switch-disabled': 'n-disabled',
'switch-focus': 'focus:outline-none focus:ring-2 focus:ring-offset-2 ring-offset-base focus:ring-brand',
// inset
'switch-inset': 'h-1.5em w-2.75em',
'switch-track-inset': 'h-1.5em w-2.75em',
// outset
'switch-outset': 'h-1.25em w-2.5em',
'switch-track-outset': 'h-1em w-2.25em',
// thumb
'switch-thumb': 'flex items-center justify-center h-1.25em w-1.25em absolute bg-base pointer-events-none inline-block transform rounded-full shadow transition-base',
'switch-thumb-on': 'translate-x-1.25em',
'switch-thumb-off': 'translate-x-0',
// track
'switch-track': 'pointer-events-none absolute mx-auto rounded-full transition-base',
'switch-track-on': 'bg-brand',
'switch-track-off': 'bg-$c-gray-200',
// icon
'switch-icon-base': 'text-0.8em',
'switch-icon-off': 'text-muted',
'switch-icon-on': 'text-muted',
// loading
'switch-loading-icon': 'i-loading',
'switch-loading': 'text-gray animate-spin text-0.8em',
}
export const dynamicSwitch = [
[/^switch-(.*)$/, ([, body]: string[], { theme }: RuleContext<Theme>) => {
const color = parseColor(body, theme)
if ((color?.cssColor?.type === 'rgb' || color?.cssColor?.type === 'rgba') && color.cssColor.components)
return `n-${body}-600 dark:n-${body}-500`
}],
]
export const _switch = [
...dynamicSwitch,
staticSwitch,
]
Component
<script setup lang="ts">
import type { NSwitchProps } from '../../types'
import { Switch } from '@headlessui/vue'
import { useVModel } from '@vueuse/core'
import { computed } from 'vue'
import NIcon from '../elements/Icon.vue'
defineOptions({
inheritAttrs: false,
})
const props = defineProps<NSwitchProps>()
const emit = defineEmits<{ (...args: any): void }>()
const on = useVModel(props, 'modelValue', emit, { passive: true })
const _switch = computed(() => props.switch)
const outsetClassVariants = computed(() => {
const switchWrapper = {
false: 'switch-inset',
true: 'switch-outset',
}
const switchTrack = {
false: 'switch-track-inset',
true: 'switch-track-outset',
}
const switchThumb = {
false: 'left-0.125em',
true: 'left-0 border-base border',
}
return {
switchWrapper: switchWrapper[!props.outset ? 'false' : 'true'],
switchTrack: switchTrack[!props.outset ? 'false' : 'true'],
switchThumb: switchThumb[!props.outset ? 'false' : 'true'],
}
})
const onClassVariants = computed(() => {
const switchTrack = {
true: `${props.una?.switchTrackOn ?? ''} switch-track-on`,
false: `${props.una?.switchTrackOff ?? ''} switch-track-off`,
}
const switchThumb = {
true: `${props.una?.switchThumbOn ?? ''} switch-thumb-on`,
false: `${props.una?.switchThumbOff ?? ''} switch-thumb-off`,
}
const switchIcon = {
true: `${props.onIcon ?? ''} switch-icon-on`,
false: `${props.offIcon ?? ''} switch-icon-off`,
}
return {
switchTrack: switchTrack[on.value ? 'true' : 'false'],
switchThumb: switchThumb[on.value ? 'true' : 'false'],
switchIcon: switchIcon[on.value ? 'true' : 'false'],
}
})
</script>
<template>
<Switch
v-model="on"
class="switch"
:class="[
{ 'switch-disabled': disabled || loading },
outsetClassVariants?.switchWrapper,
]"
:switch="_switch"
v-bind="$attrs"
:disabled="disabled"
>
<span class="sr-only">Track</span>
<span
aria-hidden="true"
switch="track"
:class="[
una?.switchTrack,
onClassVariants?.switchTrack,
outsetClassVariants?.switchTrack,
]"
/>
<span class="sr-only">Thumb</span>
<span
aria-hidden="true"
switch="thumb"
:class="[
una?.switchThumb,
onClassVariants?.switchThumb,
outsetClassVariants?.switchThumb,
]"
>
<span class="sr-only">Icon</span>
<slot v-if="!loading" name="icon" :on="on">
<NIcon
switch="icon-base"
:name="onClassVariants?.switchIcon"
:class="una?.switchIconBase"
/>
</slot>
<slot v-else name="loading-icon" :on="on">
<NIcon
switch="loading"
:class="una?.switchLoading"
:name="una?.switchloadingicon ?? 'switch-loading-icon'"
/>
</slot>
</span>
</Switch>
</template>