9.7k

原生选择框

上一页下一页

带有统一样式设计系统集成的原生 HTML 选择元素。

<script setup lang="ts">
import {
  NativeSelect,
  NativeSelectOption,
} from '@/components/ui/native-select'
</script>

<template>
  <NativeSelect>
    <NativeSelectOption value="">
      Select status
    </NativeSelectOption>
    <NativeSelectOption value="todo">
      Todo
    </NativeSelectOption>
    <NativeSelectOption value="in-progress">
      In Progress
    </NativeSelectOption>
    <NativeSelectOption value="done">
      Done
    </NativeSelectOption>
    <NativeSelectOption value="cancelled">
      Cancelled
    </NativeSelectOption>
  </NativeSelect>
</template>

安装

pnpm dlx shadcn-vue@latest add native-select

使用方法

<script setup lang="ts">
import {
  NativeSelect,
  NativeSelectOptGroup,
  NativeSelectOption,
} from '@/components/ui/native-select'
</script>

<template>
  <NativeSelect>
    <NativeSelectOption value="">
      Select a fruit
    </NativeSelectOption>
    <NativeSelectOption value="apple">
      Apple
    </NativeSelectOption>
    <NativeSelectOption value="banana">
      Banana
    </NativeSelectOption>
    <NativeSelectOption value="blueberry">
      Blueberry
    </NativeSelectOption>
    <NativeSelectOption value="grapes" disabled>
      Grapes
    </NativeSelectOption>
    <NativeSelectOption value="pineapple">
      Pineapple
    </NativeSelectOption>
  </NativeSelect>
</template>

示例

分组显示

使用 NativeSelectOptGroup 来组织选项,以实现更好的分类效果。

<script setup lang="ts">
import {
  NativeSelect,
  NativeSelectOptGroup,
  NativeSelectOption,
} from '@/components/ui/native-select'
</script>

<template>
  <NativeSelect>
    <NativeSelectOption value="">
      Select department
    </NativeSelectOption>
    <NativeSelectOptGroup label="Engineering">
      <NativeSelectOption value="frontend">
        Frontend
      </NativeSelectOption>
      <NativeSelectOption value="backend">
        Backend
      </NativeSelectOption>
      <NativeSelectOption value="devops">
        DevOps
      </NativeSelectOption>
    </NativeSelectOptGroup>
    <NativeSelectOptGroup label="Sales">
      <NativeSelectOption value="sales-rep">
        Sales Rep
      </NativeSelectOption>
      <NativeSelectOption value="account-manager">
        Account Manager
      </NativeSelectOption>
      <NativeSelectOption value="sales-director">
        Sales Director
      </NativeSelectOption>
    </NativeSelectOptGroup>
    <NativeSelectOptGroup label="Operations">
      <NativeSelectOption value="support">
        Customer Support
      </NativeSelectOption>
      <NativeSelectOption value="product-manager">
        Product Manager
      </NativeSelectOption>
      <NativeSelectOption value="ops-manager">
        Operations Manager
      </NativeSelectOption>
    </NativeSelectOptGroup>
  </NativeSelect>
</template>
<template>
  <NativeSelect>
    <NativeSelectOption value="">
      Select a food
    </NativeSelectOption>
    <NativeSelectOptGroup label="Fruits">
      <NativeSelectOption value="apple">
        Apple
      </NativeSelectOption>
      <NativeSelectOption value="banana">
        Banana
      </NativeSelectOption>
      <NativeSelectOption value="blueberry">
        Blueberry
      </NativeSelectOption>
    </NativeSelectOptGroup>
    <NativeSelectOptGroup label="Vegetables">
      <NativeSelectOption value="carrot">
        Carrot
      </NativeSelectOption>
      <NativeSelectOption value="broccoli">
        Broccoli
      </NativeSelectOption>
      <NativeSelectOption value="spinach">
        Spinach
      </NativeSelectOption>
    </NativeSelectOptGroup>
  </NativeSelect>
</template>

禁用状态

可以禁用单个选项或整个选择组件。

<script setup lang="ts">
import {
  NativeSelect,
  NativeSelectOption,
} from '@/components/ui/native-select'
</script>

<template>
  <NativeSelect disabled>
    <NativeSelectOption value="">
      Select priority
    </NativeSelectOption>
    <NativeSelectOption value="low">
      Low
    </NativeSelectOption>
    <NativeSelectOption value="medium">
      Medium
    </NativeSelectOption>
    <NativeSelectOption value="high">
      High
    </NativeSelectOption>
    <NativeSelectOption value="critical">
      Critical
    </NativeSelectOption>
  </NativeSelect>
</template>

无效状态

使用 aria-invalid 属性和错误样式来展示验证错误。

<script setup lang="ts">
import {
  NativeSelect,
  NativeSelectOption,
} from '@/components/ui/native-select'
</script>

<template>
  <NativeSelect aria-invalid="true">
    <NativeSelectOption value="">
      Select role
    </NativeSelectOption>
    <NativeSelectOption value="admin">
      Admin
    </NativeSelectOption>
    <NativeSelectOption value="editor">
      Editor
    </NativeSelectOption>
    <NativeSelectOption value="viewer">
      Viewer
    </NativeSelectOption>
    <NativeSelectOption value="guest">
      Guest
    </NativeSelectOption>
  </NativeSelect>
</template>
<template>
  <NativeSelect aria-invalid="true">
    <NativeSelectOption value="">
      Select a country
    </NativeSelectOption>
    <NativeSelectOption value="us">
      United States
    </NativeSelectOption>
    <NativeSelectOption value="uk">
      United Kingdom
    </NativeSelectOption>
    <NativeSelectOption value="ca">
      Canada
    </NativeSelectOption>
  </NativeSelect>
</template>

表单集成

可与 VeeValidate 等表单库配合使用,实现受控组件。

选择一个国家

<script setup lang="ts">
import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import { toast } from 'vue-sonner'

import { z } from 'zod'
import { Button } from '@/components/ui/button'
import {
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form'
import {
  NativeSelect,
  NativeSelectOption,
} from '@/components/ui/native-select'

const formSchema = toTypedSchema(z.object({
  country: z.string().min(2, {
    message: 'Select a country.',
  }),
}))

const form = useForm({
  validationSchema: formSchema,
})

const onSubmit = form.handleSubmit((values) => {
  console.log('Form submitted!', values)
  toast('You submitted the following values:', {
    description: h('pre', { class: 'mt-2 rounded-md bg-neutral-900 p-4 w-full' }, h('code', { class: 'text-code-foreground' }, JSON.stringify(values, null, 2))),
  })
})
</script>

<template>
  <form class="w-full max-w-sm space-y-6" @submit="onSubmit">
    <FormField v-slot="{ componentField }" name="country">
      <FormItem>
        <FormLabel>Country</FormLabel>
        <FormControl>
          <NativeSelect v-bind="(componentField as any)">
            <NativeSelectOption value="">
              Select a country
            </NativeSelectOption>
            <NativeSelectOption value="us">
              United States
            </NativeSelectOption>
            <NativeSelectOption value="uk">
              United Kingdom
            </NativeSelectOption>
            <NativeSelectOption value="ca">
              Canada
            </NativeSelectOption>
          </NativeSelect>
        </FormControl>
        <FormDescription>
          Select a country
        </FormDescription>
        <FormMessage />
      </FormItem>
    </FormField>

    <Button type="submit" class="w-full">
      Submit
    </Button>
  </form>
</template>

Native Select 与 Select 的对比

  • 当你需要原生浏览器行为、更高性能或针对移动端优化的下拉菜单时,请使用 NativeSelect
  • 当你需要自定义样式、动画或复杂交互时,请使用 Select

NativeSelect 组件提供了原生 HTML 选择功能,并具有与你的设计系统匹配的统一外观。

无障碍

  • 该组件保留了所有原生 HTML 选择框的无障碍功能。
  • 屏幕阅读器用户可以使用箭头键导航浏览选项。
  • V 形图标被标记为 aria-hidden="true" 以避免重复阅读。
  • 在需要时,可使用 aria-labelaria-labelledby 来提供更多上下文。
<template>
  <NativeSelect aria-label="Choose your preferred language">
    <NativeSelectOption value="en">
      English
    </NativeSelectOption>
    <NativeSelectOption value="es">
      Spanish
    </NativeSelectOption>
    <NativeSelectOption value="fr">
      French
    </NativeSelectOption>
  </NativeSelect>
</template>

API 参考

NativeSelect

主要的下拉选择组件,包裹了原生 HTML select 元素。

属性类型默认
classstring

所有其他属性都会传递给底层的 <select> 元素。

<NativeSelect>
  <NativeSelectOption value="option1">Option 1</NativeSelectOption>
  <NativeSelectOption value="option2">Option 2</NativeSelectOption>
</NativeSelect>

NativeSelectOption

表示下拉选择中的单个选项。

属性类型默认
valuestring
disabledbooleanfalse
classstring

所有其他属性都会传递给底层的 <option> 元素。

<template>
  <NativeSelectOption value="apple">
    Apple
  </NativeSelectOption>
  <NativeSelectOption value="banana" disabled>
    Banana
  </NativeSelectOption>
</template>

NativeSelectOptGroup

将相关选项分组在一起,以实现更好的组织。

属性类型默认
labelstring
disabledbooleanfalse
classstring

所有其他属性都会传递给底层的 <optgroup> 元素。

<template>
  <NativeSelectOptGroup label="Fruits">
    <NativeSelectOption value="apple">
      Apple
    </NativeSelectOption>
    <NativeSelectOption value="banana">
      Banana
    </NativeSelectOption>
  </NativeSelectOptGroup>
</template>