Switch

SwitchGitHub
一个在两种状态之间切换的控件。

用法

使用 v-model 指令控制开关的选中状态。

<script setup lang="ts">
const value = ref(true)
</script>

<template>
  <USwitch v-model="value" />
</template>

使用 default-value prop 在您不需要控制其状态时设置初始值。

<template>
  <USwitch default-value />
</template>

标签

使用 label 属性设置开关的标签。

<template>
  <USwitch label="Check me" />
</template>

使用 required 属性时,标签旁会添加一个星号。

<template>
  <USwitch required label="Check me" />
</template>

描述

使用 description 属性设置开关的描述。

这是一个复选框。

<template>
  <USwitch label="Check me" description="This is a checkbox." />
</template>

Icon

使用 checked-iconunchecked-icon 属性设置开关选中和未选中时的图标。

<template>
  <USwitch
    unchecked-icon="i-lucide-x"
    checked-icon="i-lucide-check"
    default-value
    label="Check me"
  />
</template>

加载中

使用 loading 属性在开关上显示加载图标。

<template>
  <USwitch loading default-value label="Check me" />
</template>

加载图标

使用 loading-icon 属性自定义加载图标。默认为 i-lucide-loader-circle

<template>
  <USwitch loading loading-icon="i-lucide-loader" default-value label="Check me" />
</template>
您可以在 app.config.ts 文件中的 ui.icons.loading 键下全局自定义此图标。
您可以在 vite.config.ts 文件中的 ui.icons.loading 键下全局自定义此图标。

颜色

使用 color 属性更改开关的颜色。

<template>
  <USwitch color="neutral" default-value label="Check me" />
</template>

尺寸

使用 size 属性更改开关的大小。

<template>
  <USwitch size="xl" default-value label="Check me" />
</template>

禁用

使用 disabled 属性禁用开关。

<template>
  <USwitch disabled label="Check me" />
</template>

API

属性

属性默认值类型
as

'div'

any

此组件应渲染为的元素或组件。

color

'primary'

"error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral"

尺寸

'md'

"xs" | "sm" | "md" | "lg" | "xl"

loading

boolean

当为 true 时,将显示加载图标。

loadingIcon

appConfig.ui.icons.loading

string

loading 属性为 true 时显示的图标。

checkedIcon

string

当开关选中时显示图标。

uncheckedIcon

string

当开关未选中时显示图标。

label

string

description

string

defaultValue

boolean

开关在初始渲染时的状态。当您不需要控制其状态时使用。

disabled

boolean

当为 true 时,阻止用户与开关交互。

id

string

name

string

字段的名称。作为名称/值对的一部分随其所属表单提交。

required

boolean

当为 true 时,表示用户必须在提交所属表单之前设置值。

value

string

当与 name 一起提交时,作为数据提供的值。

modelValue

undefined

boolean

ui

{ root?: ClassNameValue; base?: ClassNameValue; container?: ClassNameValue; thumb?: ClassNameValue; icon?: ClassNameValue; wrapper?: ClassNameValue; label?: ClassNameValue; description?: ClassNameValue; }

插槽

插槽类型
label

{ label?: string | undefined; }

description

{ description?: string | undefined; }

事件

事件类型
change

[payload: Event]

update:modelValue

[value: boolean]

主题

app.config.ts
export default defineAppConfig({
  ui: {
    switch: {
      slots: {
        root: 'relative flex items-start',
        base: [
          'inline-flex items-center shrink-0 rounded-full border-2 border-transparent focus-visible:outline-2 focus-visible:outline-offset-2 data-[state=unchecked]:bg-accented',
          'transition-[background] duration-200'
        ],
        container: 'flex items-center',
        thumb: 'group pointer-events-none rounded-full bg-default shadow-lg ring-0 transition-transform duration-200 data-[state=unchecked]:translate-x-0 data-[state=unchecked]:rtl:-translate-x-0 flex items-center justify-center',
        icon: [
          'absolute shrink-0 group-data-[state=unchecked]:text-dimmed opacity-0 size-10/12',
          'transition-[color,opacity] duration-200'
        ],
        wrapper: 'ms-2',
        label: 'block font-medium text-default',
        description: 'text-muted'
      },
      variants: {
        color: {
          primary: {
            base: 'data-[state=checked]:bg-primary focus-visible:outline-primary',
            icon: 'group-data-[state=checked]:text-primary'
          },
          secondary: {
            base: 'data-[state=checked]:bg-secondary focus-visible:outline-secondary',
            icon: 'group-data-[state=checked]:text-secondary'
          },
          success: {
            base: 'data-[state=checked]:bg-success focus-visible:outline-success',
            icon: 'group-data-[state=checked]:text-success'
          },
          info: {
            base: 'data-[state=checked]:bg-info focus-visible:outline-info',
            icon: 'group-data-[state=checked]:text-info'
          },
          warning: {
            base: 'data-[state=checked]:bg-warning focus-visible:outline-warning',
            icon: 'group-data-[state=checked]:text-warning'
          },
          error: {
            base: 'data-[state=checked]:bg-error focus-visible:outline-error',
            icon: 'group-data-[state=checked]:text-error'
          },
          neutral: {
            base: 'data-[state=checked]:bg-inverted focus-visible:outline-inverted',
            icon: 'group-data-[state=checked]:text-highlighted'
          }
        },
        size: {
          xs: {
            base: 'w-7',
            container: 'h-4',
            thumb: 'size-3 data-[state=checked]:translate-x-3 data-[state=checked]:rtl:-translate-x-3',
            wrapper: 'text-xs'
          },
          sm: {
            base: 'w-8',
            container: 'h-4',
            thumb: 'size-3.5 data-[state=checked]:translate-x-3.5 data-[state=checked]:rtl:-translate-x-3.5',
            wrapper: 'text-xs'
          },
          md: {
            base: 'w-9',
            container: 'h-5',
            thumb: 'size-4 data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4',
            wrapper: 'text-sm'
          },
          lg: {
            base: 'w-10',
            container: 'h-5',
            thumb: 'size-4.5 data-[state=checked]:translate-x-4.5 data-[state=checked]:rtl:-translate-x-4.5',
            wrapper: 'text-sm'
          },
          xl: {
            base: 'w-11',
            container: 'h-6',
            thumb: 'size-5 data-[state=checked]:translate-x-5 data-[state=checked]:rtl:-translate-x-5',
            wrapper: 'text-base'
          }
        },
        checked: {
          true: {
            icon: 'group-data-[state=checked]:opacity-100'
          }
        },
        unchecked: {
          true: {
            icon: 'group-data-[state=unchecked]:opacity-100'
          }
        },
        loading: {
          true: {
            icon: 'animate-spin'
          }
        },
        required: {
          true: {
            label: "after:content-['*'] after:ms-0.5 after:text-error"
          }
        },
        disabled: {
          true: {
            base: 'cursor-not-allowed opacity-75',
            label: 'cursor-not-allowed opacity-75',
            description: 'cursor-not-allowed opacity-75'
          }
        }
      },
      defaultVariants: {
        color: 'primary',
        size: 'md'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        switch: {
          slots: {
            root: 'relative flex items-start',
            base: [
              'inline-flex items-center shrink-0 rounded-full border-2 border-transparent focus-visible:outline-2 focus-visible:outline-offset-2 data-[state=unchecked]:bg-accented',
              'transition-[background] duration-200'
            ],
            container: 'flex items-center',
            thumb: 'group pointer-events-none rounded-full bg-default shadow-lg ring-0 transition-transform duration-200 data-[state=unchecked]:translate-x-0 data-[state=unchecked]:rtl:-translate-x-0 flex items-center justify-center',
            icon: [
              'absolute shrink-0 group-data-[state=unchecked]:text-dimmed opacity-0 size-10/12',
              'transition-[color,opacity] duration-200'
            ],
            wrapper: 'ms-2',
            label: 'block font-medium text-default',
            description: 'text-muted'
          },
          variants: {
            color: {
              primary: {
                base: 'data-[state=checked]:bg-primary focus-visible:outline-primary',
                icon: 'group-data-[state=checked]:text-primary'
              },
              secondary: {
                base: 'data-[state=checked]:bg-secondary focus-visible:outline-secondary',
                icon: 'group-data-[state=checked]:text-secondary'
              },
              success: {
                base: 'data-[state=checked]:bg-success focus-visible:outline-success',
                icon: 'group-data-[state=checked]:text-success'
              },
              info: {
                base: 'data-[state=checked]:bg-info focus-visible:outline-info',
                icon: 'group-data-[state=checked]:text-info'
              },
              warning: {
                base: 'data-[state=checked]:bg-warning focus-visible:outline-warning',
                icon: 'group-data-[state=checked]:text-warning'
              },
              error: {
                base: 'data-[state=checked]:bg-error focus-visible:outline-error',
                icon: 'group-data-[state=checked]:text-error'
              },
              neutral: {
                base: 'data-[state=checked]:bg-inverted focus-visible:outline-inverted',
                icon: 'group-data-[state=checked]:text-highlighted'
              }
            },
            size: {
              xs: {
                base: 'w-7',
                container: 'h-4',
                thumb: 'size-3 data-[state=checked]:translate-x-3 data-[state=checked]:rtl:-translate-x-3',
                wrapper: 'text-xs'
              },
              sm: {
                base: 'w-8',
                container: 'h-4',
                thumb: 'size-3.5 data-[state=checked]:translate-x-3.5 data-[state=checked]:rtl:-translate-x-3.5',
                wrapper: 'text-xs'
              },
              md: {
                base: 'w-9',
                container: 'h-5',
                thumb: 'size-4 data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4',
                wrapper: 'text-sm'
              },
              lg: {
                base: 'w-10',
                container: 'h-5',
                thumb: 'size-4.5 data-[state=checked]:translate-x-4.5 data-[state=checked]:rtl:-translate-x-4.5',
                wrapper: 'text-sm'
              },
              xl: {
                base: 'w-11',
                container: 'h-6',
                thumb: 'size-5 data-[state=checked]:translate-x-5 data-[state=checked]:rtl:-translate-x-5',
                wrapper: 'text-base'
              }
            },
            checked: {
              true: {
                icon: 'group-data-[state=checked]:opacity-100'
              }
            },
            unchecked: {
              true: {
                icon: 'group-data-[state=unchecked]:opacity-100'
              }
            },
            loading: {
              true: {
                icon: 'animate-spin'
              }
            },
            required: {
              true: {
                label: "after:content-['*'] after:ms-0.5 after:text-error"
              }
            },
            disabled: {
              true: {
                base: 'cursor-not-allowed opacity-75',
                label: 'cursor-not-allowed opacity-75',
                description: 'cursor-not-allowed opacity-75'
              }
            }
          },
          defaultVariants: {
            color: 'primary',
            size: 'md'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        switch: {
          slots: {
            root: 'relative flex items-start',
            base: [
              'inline-flex items-center shrink-0 rounded-full border-2 border-transparent focus-visible:outline-2 focus-visible:outline-offset-2 data-[state=unchecked]:bg-accented',
              'transition-[background] duration-200'
            ],
            container: 'flex items-center',
            thumb: 'group pointer-events-none rounded-full bg-default shadow-lg ring-0 transition-transform duration-200 data-[state=unchecked]:translate-x-0 data-[state=unchecked]:rtl:-translate-x-0 flex items-center justify-center',
            icon: [
              'absolute shrink-0 group-data-[state=unchecked]:text-dimmed opacity-0 size-10/12',
              'transition-[color,opacity] duration-200'
            ],
            wrapper: 'ms-2',
            label: 'block font-medium text-default',
            description: 'text-muted'
          },
          variants: {
            color: {
              primary: {
                base: 'data-[state=checked]:bg-primary focus-visible:outline-primary',
                icon: 'group-data-[state=checked]:text-primary'
              },
              secondary: {
                base: 'data-[state=checked]:bg-secondary focus-visible:outline-secondary',
                icon: 'group-data-[state=checked]:text-secondary'
              },
              success: {
                base: 'data-[state=checked]:bg-success focus-visible:outline-success',
                icon: 'group-data-[state=checked]:text-success'
              },
              info: {
                base: 'data-[state=checked]:bg-info focus-visible:outline-info',
                icon: 'group-data-[state=checked]:text-info'
              },
              warning: {
                base: 'data-[state=checked]:bg-warning focus-visible:outline-warning',
                icon: 'group-data-[state=checked]:text-warning'
              },
              error: {
                base: 'data-[state=checked]:bg-error focus-visible:outline-error',
                icon: 'group-data-[state=checked]:text-error'
              },
              neutral: {
                base: 'data-[state=checked]:bg-inverted focus-visible:outline-inverted',
                icon: 'group-data-[state=checked]:text-highlighted'
              }
            },
            size: {
              xs: {
                base: 'w-7',
                container: 'h-4',
                thumb: 'size-3 data-[state=checked]:translate-x-3 data-[state=checked]:rtl:-translate-x-3',
                wrapper: 'text-xs'
              },
              sm: {
                base: 'w-8',
                container: 'h-4',
                thumb: 'size-3.5 data-[state=checked]:translate-x-3.5 data-[state=checked]:rtl:-translate-x-3.5',
                wrapper: 'text-xs'
              },
              md: {
                base: 'w-9',
                container: 'h-5',
                thumb: 'size-4 data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4',
                wrapper: 'text-sm'
              },
              lg: {
                base: 'w-10',
                container: 'h-5',
                thumb: 'size-4.5 data-[state=checked]:translate-x-4.5 data-[state=checked]:rtl:-translate-x-4.5',
                wrapper: 'text-sm'
              },
              xl: {
                base: 'w-11',
                container: 'h-6',
                thumb: 'size-5 data-[state=checked]:translate-x-5 data-[state=checked]:rtl:-translate-x-5',
                wrapper: 'text-base'
              }
            },
            checked: {
              true: {
                icon: 'group-data-[state=checked]:opacity-100'
              }
            },
            unchecked: {
              true: {
                icon: 'group-data-[state=unchecked]:opacity-100'
              }
            },
            loading: {
              true: {
                icon: 'animate-spin'
              }
            },
            required: {
              true: {
                label: "after:content-['*'] after:ms-0.5 after:text-error"
              }
            },
            disabled: {
              true: {
                base: 'cursor-not-allowed opacity-75',
                label: 'cursor-not-allowed opacity-75',
                description: 'cursor-not-allowed opacity-75'
              }
            }
          },
          defaultVariants: {
            color: 'primary',
            size: 'md'
          }
        }
      }
    })
  ]
})