Skip to main content
PolyUI/docs

Select 选择器

下拉选择器,支持禁用单个选项与完整键盘导航,基于 Base UI Select 构建。

安装

bash
npx polyui add select

原生默认

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeDefault() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select default</Label>
      <NativeSelect id={id}>
        <NativeSelectOption value="1">Male</NativeSelectOption>
        <NativeSelectOption value="2">Female</NativeSelectOption>
        <NativeSelectOption value="3">Other</NativeSelectOption>
      </NativeSelect>
    </div>
  )
}

原生占位符

tsx
import { useId } from "react"
import { Select } from "@polyui/react/select"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeWithPlaceholder() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select with placeholder</Label>
      <NativeSelect id={id} defaultValue="">
        <NativeSelectOption value="" disabled>
          Select gender
        </NativeSelectOption>
        <NativeSelectOption value="1">Male</NativeSelectOption>
        <NativeSelectOption value="2">Female</NativeSelectOption>
        <NativeSelectOption value="3">Other</NativeSelectOption>
      </NativeSelect>
    </div>
  )
}

原生带图标

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
import { FilmIcon } from "lucide-react"
export function SelectNativeWithIcon() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select with icon</Label>
      <div className="group relative">
        <NativeSelect id={id} className="pl-9" defaultValue="">
          <NativeSelectOption value="" disabled>
            Pick a movie
          </NativeSelectOption>
          <NativeSelectOption value="1">Godfather</NativeSelectOption>
          <NativeSelectOption value="2">A Working Man</NativeSelectOption>
          <NativeSelectOption value="3">The Dark Knight</NativeSelectOption>
          <NativeSelectOption value="4">Inception</NativeSelectOption>
        </NativeSelect>
        <div className="text-muted-foreground/80 pointer-events-none absolute inset-y-0 left-0 flex items-center justify-center pl-3 group-has-[select[disabled]]:opacity-50">
          <FilmIcon size={16} aria-hidden="true" />
        </div>
      </div>
    </div>
  )
}

原生辅助文字

Select the city you reside in.

tsx
import { useId } from "react"
import { Select } from "@polyui/react/select"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeWithHelperText() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select with helper text</Label>
      <NativeSelect id={id}>
        <NativeSelectOption value="1">Florida</NativeSelectOption>
        <NativeSelectOption value="2">California</NativeSelectOption>
        <NativeSelectOption value="3">San Francisco</NativeSelectOption>
        <NativeSelectOption value="4">Alabama</NativeSelectOption>
      </NativeSelect>
      <p className="text-muted-foreground mt-2 text-xs" role="region" aria-live="polite">
        Select the city you reside in.
      </p>
    </div>
  )
}

原生错误状态

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeWithError() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select with error</Label>
      <NativeSelect id={id} aria-invalid>
        <NativeSelectOption value="1">IST (Indian Standard Time)</NativeSelectOption>
        <NativeSelectOption value="2">EST (Eastern Standard Time)</NativeSelectOption>
        <NativeSelectOption value="3">PST (Pacific Standard Time)</NativeSelectOption>
        <NativeSelectOption value="4">GMT (Greenwich Mean Time)</NativeSelectOption>
      </NativeSelect>
      <p className="text-destructive mt-2 text-xs" role="alert" aria-live="polite">
        Please select a valid option.
      </p>
    </div>
  )
}

原生必填

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeRequired() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id} className="gap-1">
        Native select required <span className="text-destructive">*</span>
      </Label>
      <NativeSelect id={id} required>
        <NativeSelectOption value="1">Action</NativeSelectOption>
        <NativeSelectOption value="2">Comedy</NativeSelectOption>
        <NativeSelectOption value="3">Romance</NativeSelectOption>
        <NativeSelectOption value="4">Thriller</NativeSelectOption>
      </NativeSelect>
    </div>
  )
}

原生选项组

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption, NativeSelectOptGroup } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeWithOptionGroups() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select with option groups</Label>
      <NativeSelect id={id}>
        <NativeSelectOptGroup label="Frontend Technologies">
          <NativeSelectOption value="1">HTML</NativeSelectOption>
          <NativeSelectOption value="2">CSS</NativeSelectOption>
          <NativeSelectOption value="3">JavaScript</NativeSelectOption>
        </NativeSelectOptGroup>
        <NativeSelectOptGroup label="Backend Technologies">
          <NativeSelectOption value="4">Node.js</NativeSelectOption>
          <NativeSelectOption value="5">Python</NativeSelectOption>
          <NativeSelectOption value="6">Java</NativeSelectOption>
        </NativeSelectOptGroup>
      </NativeSelect>
    </div>
  )
}

原生悬浮标签

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
export function SelectNativeOverlappingLabel() {
  const id = useId()
  return (
    <div className="group relative w-full max-w-xs">
      <label
        htmlFor={id}
        className="bg-background text-foreground absolute top-0 left-2 z-10 block -translate-y-1/2 px-1 text-xs font-medium group-has-[select[disabled]]:opacity-50"
      >
        Overlapping label
      </label>
      <NativeSelect id={id}>
        <NativeSelectOption value="1">Developer</NativeSelectOption>
        <NativeSelectOption value="2">Designer</NativeSelectOption>
        <NativeSelectOption value="3">Manager</NativeSelectOption>
        <NativeSelectOption value="4">QA Engineer</NativeSelectOption>
      </NativeSelect>
    </div>
  )
}

原生内嵌标签

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
export function SelectNativeInsetLabel() {
  const id = useId()
  return (
    <div className="border-input bg-background focus-within:border-ring focus-within:ring-ring/50 has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive relative w-full max-w-xs rounded-md border shadow-xs transition-[color,box-shadow] outline-none focus-within:ring-[3px] has-[select:disabled]:cursor-not-allowed has-[select:disabled]:opacity-50">
      <label htmlFor={id} className="text-foreground block px-3 pt-1 text-xs font-medium">
        Inset label
      </label>
      <NativeSelect id={id} defaultValue="" className="border-none bg-transparent shadow-none focus-visible:ring-0">
        <NativeSelectOption value="" disabled>
          Pick a movie
        </NativeSelectOption>
        <NativeSelectOption value="1">Interstellar</NativeSelectOption>
        <NativeSelectOption value="2">Dune</NativeSelectOption>
        <NativeSelectOption value="3">The Matrix</NativeSelectOption>
        <NativeSelectOption value="4">Catch Me If You Can</NativeSelectOption>
      </NativeSelect>
    </div>
  )
}

默认

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectDefault() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Select default</Label>
      <Select defaultValue="apple">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
            <SelectItem value="grapes">Grapes</SelectItem>
            <SelectItem value="pineapple">Pineapple</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

带占位符

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithPlaceholder() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Select with placeholder</Label>
      <Select>
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
            <SelectItem value="grapes">Grapes</SelectItem>
            <SelectItem value="pineapple">Pineapple</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

带图标

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
import { FilmIcon } from "lucide-react"
export function SelectWithIcon() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Select with icon</Label>
      <Select defaultValue="god of wars">
        <SelectTrigger id={id} className="relative w-full pl-9">
          <div className="text-muted-foreground/80 pointer-events-none absolute inset-y-0 left-0 flex items-center justify-center pl-3">
            <FilmIcon size={16} aria-hidden="true" />
          </div>
          <SelectValue placeholder="Select a time" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="god of wars">God of Wars</SelectItem>
          <SelectItem value="ghost rider">Ghost Rider</SelectItem>
          <SelectItem value="the cloth">The Cloth</SelectItem>
          <SelectItem value="the possession">The Possession</SelectItem>
        </SelectContent>
      </Select>
    </div>
  )
}

带辅助文字

Select the city you reside in.

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithHelperText() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Select with helper text</Label>
      <Select defaultValue="3">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">Florida</SelectItem>
          <SelectItem value="2">New York</SelectItem>
          <SelectItem value="3">California</SelectItem>
          <SelectItem value="4">Texas</SelectItem>
        </SelectContent>
      </Select>
      <p className="text-muted-foreground mt-2 text-xs" role="region" aria-live="polite">
        Select the city you reside in.
      </p>
    </div>
  )
}

错误状态

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithError() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Select with error</Label>
      <Select defaultValue="1">
        <SelectTrigger id={id} aria-invalid className="w-full">
          <SelectValue />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">Tesla</SelectItem>
          <SelectItem value="2">BMW</SelectItem>
          <SelectItem value="3">Audi</SelectItem>
          <SelectItem value="4">Mercedes-Benz</SelectItem>
        </SelectContent>
      </Select>
      <p className="text-destructive mt-2 text-xs" role="alert" aria-live="polite">
        Please select a valid option.
      </p>
    </div>
  )
}

尺寸

tsx
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
export function SelectSizes() {
  return (
    <div className="w-full max-w-xs space-y-2">
      <Select>
        <SelectTrigger size="sm" className="w-full">
          <SelectValue placeholder="Small select" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
      <Select>
        <SelectTrigger className="w-full">
          <SelectValue placeholder="Default select" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
      <Select>
        <SelectTrigger className="!h-10 w-full">
          <SelectValue placeholder="Large select" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

彩色边框

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectColoredBorder() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Colored border</Label>
      <Select defaultValue="1">
        <SelectTrigger
          id={id}
          className="w-full focus-visible:border-indigo-500 focus-visible:ring-indigo-500/20 dark:focus-visible:ring-indigo-500/40"
        >
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">Electronics</SelectItem>
          <SelectItem value="2">Clothing</SelectItem>
          <SelectItem value="3">Home Appliances</SelectItem>
          <SelectItem value="4">Books</SelectItem>
        </SelectContent>
      </Select>
    </div>
  )
}

背景颜色

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectBackgroundColor() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Background color</Label>
      <Select defaultValue="hindi">
        <SelectTrigger className="w-full border-sky-600 bg-sky-600/10 text-sky-600 shadow-none focus-visible:border-sky-600 focus-visible:ring-sky-600/20 dark:bg-sky-400/10 dark:text-sky-400 dark:hover:bg-sky-400/10 dark:focus-visible:ring-sky-400/40 [&_svg]:!text-sky-600 dark:[&_svg]:!text-sky-400">
          <SelectValue placeholder="Select a language" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup className="[&_div:focus]:bg-sky-600/20 [&_div:focus]:text-sky-600 dark:[&_div:focus]:bg-sky-400/20 dark:[&_div:focus]:text-sky-400">
            <SelectLabel>Languages</SelectLabel>
            <SelectItem value="hindi">Hindi</SelectItem>
            <SelectItem value="english">English</SelectItem>
            <SelectItem value="spanish">Spanish</SelectItem>
            <SelectItem value="mandarin">Mandarin</SelectItem>
            <SelectItem value="french">French</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

幽灵样式

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectGhost() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Ghost</Label>
      <Select defaultValue="apple">
        <SelectTrigger className="hover:bg-accent w-full border-none shadow-none dark:bg-transparent">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
            <SelectItem value="grapes">Grapes</SelectItem>
            <SelectItem value="pineapple">Pineapple</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

禁用

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectDisabled() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Disabled</Label>
      <Select defaultValue="apple" disabled>
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

禁用选项

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectDisabledOptions() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Disabled options</Label>
      <Select defaultValue="apple">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana" disabled>
              Banana
            </SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
            <SelectItem value="grapes" disabled>
              Grapes
            </SelectItem>
            <SelectItem value="pineapple">Pineapple</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

必填

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectRequired() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id} className="gap-1">
        Required <span className="text-destructive">*</span>
      </Label>
      <Select defaultValue="2">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">United States</SelectItem>
          <SelectItem value="2">Japan</SelectItem>
          <SelectItem value="3">Australia</SelectItem>
          <SelectItem value="4">Brazil</SelectItem>
        </SelectContent>
      </Select>
    </div>
  )
}

带选项组

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithOptionGroups() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>With option groups</Label>
      <Select defaultValue="7">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>North America</SelectLabel>
            <SelectItem value="1">United States</SelectItem>
            <SelectItem value="2">Canada</SelectItem>
            <SelectItem value="3">Mexico</SelectItem>
          </SelectGroup>
          <SelectGroup>
            <SelectLabel>Europe</SelectLabel>
            <SelectItem value="4">United Kingdom</SelectItem>
            <SelectItem value="5">Germany</SelectItem>
            <SelectItem value="6">France</SelectItem>
          </SelectGroup>
          <SelectGroup>
            <SelectLabel>Asia</SelectLabel>
            <SelectItem value="7">India</SelectItem>
            <SelectItem value="8">Japan</SelectItem>
            <SelectItem value="9">China</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

带分隔线

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithSeparator() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>With separator</Label>
      <Select defaultValue="7">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>North America</SelectLabel>
            <SelectItem value="1">United States</SelectItem>
            <SelectItem value="2">Canada</SelectItem>
            <SelectItem value="3">Mexico</SelectItem>
          </SelectGroup>
          <SelectSeparator />
          <SelectGroup>
            <SelectLabel>Europe</SelectLabel>
            <SelectItem value="4">United Kingdom</SelectItem>
            <SelectItem value="5">Germany</SelectItem>
            <SelectItem value="6">France</SelectItem>
          </SelectGroup>
          <SelectSeparator />
          <SelectGroup>
            <SelectLabel>Asia</SelectLabel>
            <SelectItem value="7">India</SelectItem>
            <SelectItem value="8">Japan</SelectItem>
            <SelectItem value="9">China</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

悬浮标签

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
export function SelectOverlappingLabel() {
  const id = useId()
  return (
    <div className="group relative w-full max-w-xs">
      <label
        htmlFor={id}
        className="bg-background text-foreground absolute top-0 left-2 z-10 block -translate-y-1/2 px-1 text-xs font-medium group-has-disabled:opacity-50"
      >
        Overlapping label
      </label>
      <Select>
        <SelectTrigger id={id} className="dark:!bg-background w-full">
          <SelectValue placeholder="Select a city" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">New York</SelectItem>
          <SelectItem value="2">London</SelectItem>
          <SelectItem value="3">Tokyo</SelectItem>
          <SelectItem value="4">Paris</SelectItem>
        </SelectContent>
      </Select>
    </div>
  )
}

内嵌标签

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
export function SelectInsetLabel() {
  const id = useId()
  return (
    <div className="border-input group bg-background focus-within:border-ring focus-within:ring-ring/50 has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive relative w-full max-w-xs rounded-md border shadow-xs transition-[color,box-shadow] outline-none focus-within:ring-[3px] has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50">
      <label
        htmlFor={id}
        className="text-foreground dark:bg-input/30 dark:group-hover:bg-input/50 block px-3 pt-1 text-xs font-medium"
      >
        Inset label
      </label>
      <Select>
        <SelectTrigger
          id={id}
          className="dark:group-hover:bg-input/50 w-full rounded-t-none border-none bg-transparent shadow-none focus-visible:ring-0"
        >
          <SelectValue placeholder="Select payment method" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">Credit Card</SelectItem>
          <SelectItem value="2">Google Pay</SelectItem>
          <SelectItem value="3">PayPal</SelectItem>
          <SelectItem value="4">Bitcoin</SelectItem>
        </SelectContent>
      </Select>
    </div>
  )
}

时区

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectTimezone() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Timezone</Label>
      <Select>
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a timezone" />
        </SelectTrigger>
        <SelectContent className="max-h-100">
          <SelectGroup>
            <SelectLabel>North America</SelectLabel>
            <SelectItem value="est">Eastern Standard Time (EST)</SelectItem>
            <SelectItem value="cst">Central Standard Time (CST)</SelectItem>
            <SelectItem value="pst">Pacific Standard Time (PST)</SelectItem>
            <SelectItem value="hst">Hawaii Standard Time (HST)</SelectItem>
          </SelectGroup>
          <SelectGroup>
            <SelectLabel>Europe &amp; Africa</SelectLabel>
            <SelectItem value="gmt">Greenwich Mean Time (GMT)</SelectItem>
            <SelectItem value="cet">Central European Time (CET)</SelectItem>
            <SelectItem value="eet">Eastern European Time (EET)</SelectItem>
          </SelectGroup>
          <SelectGroup>
            <SelectLabel>Asia</SelectLabel>
            <SelectItem value="ist">India Standard Time (IST)</SelectItem>
            <SelectItem value="jst">Japan Standard Time (JST)</SelectItem>
            <SelectItem value="kst">Korea Standard Time (KST)</SelectItem>
          </SelectGroup>
          <SelectGroup>
            <SelectLabel>Australia &amp; Pacific</SelectLabel>
            <SelectItem value="aest">Australian Eastern Standard Time (AEST)</SelectItem>
            <SelectItem value="nzst">New Zealand Standard Time (NZST)</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

选项带图标

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
import { GuitarIcon, HeadphonesIcon, MicVocalIcon, MusicIcon } from "lucide-react"
export function SelectOptionsWithIcon() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Options with icon</Label>
      <Select defaultValue="rock">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a music genre" />
        </SelectTrigger>
        <SelectContent>
          <SelectGroup>
            <SelectLabel>Music Genres</SelectLabel>
            <SelectItem value="rock">
              <GuitarIcon />
              Rock
            </SelectItem>
            <SelectItem value="electronic">
              <HeadphonesIcon />
              Electronic
            </SelectItem>
            <SelectItem value="pop">
              <MicVocalIcon />
              Pop
            </SelectItem>
            <SelectItem value="jazz">
              <MusicIcon />
              Jazz
            </SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

带前置文字

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithLeadingText() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>With leading text</Label>
      <Select defaultValue="1">
        <SelectTrigger id={id} className="w-full">
          <span>
            Favorite movie: <SelectValue placeholder="Select a movie" />
          </span>
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="1">Inception</SelectItem>
          <SelectItem value="2">Interstellar</SelectItem>
          <SelectItem value="3">The Dark Knight</SelectItem>
          <SelectItem value="4">Pulp Fiction</SelectItem>
        </SelectContent>
      </Select>
    </div>
  )
}

状态

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
import { CircleIcon } from "lucide-react"
export function SelectStatus() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Status</Label>
      <Select defaultValue="1">
        <SelectTrigger
          id={id}
          className="w-full [&>span]:flex [&>span]:items-center [&>span]:gap-2 [&>span_svg]:shrink-0"
        >
          <SelectValue placeholder="Select a status" />
        </SelectTrigger>
        <SelectContent className="[&_*[role=option]>span>svg]:text-muted-foreground/80 [&_*[role=option]]:pr-8 [&_*[role=option]]:pl-2 [&_*[role=option]>span]:right-2 [&_*[role=option]>span]:left-auto [&_*[role=option]>span]:flex [&_*[role=option]>span]:items-center [&_*[role=option]>span]:gap-2 [&_*[role=option]>span>svg]:shrink-0">
          {[
            { value: "1", label: "In Progress", color: "fill-violet-500 text-violet-500" },
            { value: "2", label: "Pending", color: "fill-amber-500 text-amber-500" },
            { value: "3", label: "Completed", color: "fill-emerald-600 text-emerald-600" },
            { value: "4", label: "Cancelled", color: "fill-gray-500 text-gray-500" },
            { value: "5", label: "Rejected", color: "fill-red-500 text-red-500" },
          ].map(({ value, label, color }) => (
            <SelectItem key={value} value={value}>
              <span className="flex items-center gap-2">
                <CircleIcon className={`size-2 ${color}`} />
                <span className="truncate">{label}</span>
              </span>
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    </div>
  )
}

带国旗

tsx
import { useId } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectWithFlags() {
  const id = useId()
  const countries = [
    { value: "1", label: "India", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/india.png" },
    { value: "2", label: "China", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/china.png" },
    { value: "3", label: "Monaco", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/monaco.png" },
    { value: "4", label: "Serbia", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/serbia.png" },
    { value: "5", label: "Romania", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/romania.png" },
    { value: "6", label: "Iraq", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/iraq.png" },
    { value: "7", label: "Korea", flag: "https://cdn.shadcnstudio.com/ss-assets/flags/korea.png" },
  ]
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>With flags</Label>
      <Select defaultValue="1">
        <SelectTrigger
          id={id}
          className="w-full [&>span]:flex [&>span]:items-center [&>span]:gap-2 [&>span_svg]:shrink-0"
        >
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent className="max-h-100 [&_*[role=option]]:pr-8 [&_*[role=option]]:pl-2 [&_*[role=option]>span]:right-2 [&_*[role=option]>span]:left-auto [&_*[role=option]>span]:flex [&_*[role=option]>span]:items-center [&_*[role=option]>span]:gap-2">
          {countries.map((country) => (
            <SelectItem key={country.value} value={country.value}>
              <img src={country.flag} alt={`${country.label} flag`} className="h-4 w-5" />
              <span className="truncate">{country.label}</span>
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    </div>
  )
}

带头像

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
export function SelectWithAvatars() {
  const id = useId()
  const users = [
    {
      id: "1",
      src: "https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-1.png",
      fallback: "PG",
      name: "Phillip George",
    },
    {
      id: "2",
      src: "https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-2.png",
      fallback: "JD",
      name: "Jaylon Donin",
    },
    {
      id: "3",
      src: "https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-3.png",
      fallback: "TC",
      name: "Tiana Curtis",
    },
  ]
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>With avatars</Label>
      <Select defaultValue="1">
        <SelectTrigger
          id={id}
          className="w-full pl-2 [&>span]:flex [&>span]:items-center [&>span]:gap-2 [&>span_img]:shrink-0"
        >
          <SelectValue placeholder="Select a framework" />
        </SelectTrigger>
        <SelectContent className="[&_*[role=option]]:pr-8 [&_*[role=option]]:pl-2 [&_*[role=option]>span]:right-2 [&_*[role=option]>span]:left-auto [&_*[role=option]>span]:flex [&_*[role=option]>span]:items-center [&_*[role=option]>span]:gap-2">
          <SelectGroup>
            <SelectLabel className="pl-2">Impersonate user</SelectLabel>
            {users.map((item) => (
              <SelectItem key={item.id} value={item.id}>
                <Avatar className="size-5">
                  <AvatarImage src={item.src} alt={item.name} className="rounded-full" />
                  <AvatarFallback className="text-xs">{item.fallback}</AvatarFallback>
                </Avatar>
                <span className="truncate">{item.name}</span>
              </SelectItem>
            ))}
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

原生多选

tsx
import { useId } from "react"
import { NativeSelect, NativeSelectOption } from "@polyui/react/native-select"
import { Label } from "@polyui/react/label"
export function SelectNativeMultiple() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Native select multiple</Label>
      <div className="border-input overflow-hidden rounded-md border">
        <NativeSelect id={id} multiple className="rounded-none border-none">
          <NativeSelectOption value="1">Vegetarian</NativeSelectOption>
          <NativeSelectOption value="2">Vegan</NativeSelectOption>
          <NativeSelectOption value="3">Gluten-Free</NativeSelectOption>
          <NativeSelectOption value="4">Halal</NativeSelectOption>
          <NativeSelectOption value="5">Kosher</NativeSelectOption>
          <NativeSelectOption value="6">Dairy-Free</NativeSelectOption>
        </NativeSelect>
      </div>
    </div>
  )
}

滑入

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectSlideIn() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Slide-in animation</Label>
      <Select defaultValue="apple">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent className="data-[state=open]:slide-in-from-bottom-8 data-[state=open]:zoom-in-100 duration-400">
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
            <SelectItem value="grapes">Grapes</SelectItem>
            <SelectItem value="pineapple">Pineapple</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

缩放动画

tsx
import { useId } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@polyui/react/select"
import { Label } from "@polyui/react/label"
export function SelectZoomIn() {
  const id = useId()
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Zoom-in animation</Label>
      <Select defaultValue="apple">
        <SelectTrigger id={id} className="w-full">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent className="data-[state=open]:!zoom-in-0 origin-center duration-400">
          <SelectGroup>
            <SelectLabel>Fruits</SelectLabel>
            <SelectItem value="apple">Apple</SelectItem>
            <SelectItem value="banana">Banana</SelectItem>
            <SelectItem value="blueberry">Blueberry</SelectItem>
            <SelectItem value="grapes">Grapes</SelectItem>
            <SelectItem value="pineapple">Pineapple</SelectItem>
          </SelectGroup>
        </SelectContent>
      </Select>
    </div>
  )
}

属性 — Select

属性类型默认值说明
valuestring当前选中的值(受控模式)。
onValueChange(value: string) => void选中值变化时的回调函数。
disabledbooleanfalse禁用整个选择器,阻止用户交互。
placeholderstring未选中时触发器显示的占位文本。

属性 — SelectItem

属性类型默认值说明
valuestring该选项的值,必填,用于标识和受控绑定。
disabledbooleanfalse禁用该选项,禁用后仍在列表中显示但不可选择。