当用户需要从一组同类数据中选择一个或多个时,可以使用下拉选择器,点击后选择对应项。

演示

import { Select, SelectContent, SelectList, SelectEmpty } from "@resolid/react-ui";

export default function App() {
  const collection = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "blueberry", label: "Blueberry" },
    { value: "grapes", label: "Grapes", disabled: true },
    { value: "pineapple", label: "Pineapple" },
  ];

  return (
    <Select placeholder="选择器" className="w-50" collection={collection}>
      <SelectContent className="p-1">
        <SelectEmpty />
        <SelectList />
      </SelectContent>
    </Select>
  );
}

用法

import {
  Select,
  SelectFilter,
  SelectContent,
  SelectEmpty,
  SelectVirtualizer,
  SelectList,
} from "@resolid/react-ui";
  • Select: 选择器的根容器。
  • SelectFilter: 选择器筛选。
  • SelectContent: 选择器要渲染的内容。
  • SelectEmpty: 选择器搜索结果为空时显示。
  • SelectVirtualizer: 选择器列表虚拟化。
  • SelectList: 选择器的项目列表。
<Select>
  <SelectFilter />
  <SelectContent>
    <SelectEmpty />
    <SelectList />
  </SelectContent>
</Select>

特点

  • 使用 WAI ARIA Listbox 设计模式作为 Select 辅助技术。
  • 可以控制或不受控制。
  • 全键盘导航。
  • 支持单选和多选。
  • 支持禁用选项。
  • 支持项目、标签、项目组。
  • 支持自定义占位符。

举例

可控值

使用 valueonChange 属性来控制选择的值。

你选择了水果:

import { Select, SelectContent, SelectList } from "@resolid/react-ui";
import { useState } from "react";

export default function App() {
  const [value, setValue] = useState();

  const collection = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "blueberry", label: "Blueberry" },
    { value: "grapes", label: "Grapes", disabled: true },
    { value: "pineapple", label: "Pineapple" },
  ];

  return (
    <div className="flex flex-col gap-2">
      <p>你选择了水果: {value}</p>
      <Select
        placeholder="选择器"
        className="w-50"
        value={value}
        onChange={setValue}
        collection={collection}
      >
        <SelectContent className="p-1">
          <SelectList />
        </SelectContent>
      </Select>
    </div>
  );
}

默认值

import { Select, SelectContent, SelectList } from "@resolid/react-ui";

export default function App() {
  const collection = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "blueberry", label: "Blueberry" },
    { value: "grapes", label: "Grapes", disabled: true },
    { value: "pineapple", label: "Pineapple" },
  ];

  return (
    <div className="flex gap-3">
      <Select
        placeholder="选择器"
        defaultValue="blueberry"
        className="w-50"
        collection={collection}
      >
        <SelectContent className="p-1">
          <SelectList />
        </SelectContent>
      </Select>
      <Select
        placeholder="选择器"
        multiple
        defaultValue={["apple", "pineapple"]}
        className="min-w-50"
        collection={collection}
      >
        <SelectContent className="p-1">
          <SelectList />
        </SelectContent>
      </Select>
    </div>
  );
}

多选

import { Select, SelectContent, SelectList } from "@resolid/react-ui";

export default function App() {
  const collection = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "blueberry", label: "Blueberry" },
    { value: "grapes", label: "Grapes", disabled: true },
    { value: "pineapple", label: "Pineapple" },
  ];

  return (
    <Select placeholder="选择器" className="min-w-50" multiple collection={collection}>
      <SelectContent className="p-1">
        <SelectList />
      </SelectContent>
    </Select>
  );
}

可筛选

import { Select, SelectFilter, SelectContent, SelectEmpty, SelectList } from "@resolid/react-ui";

export default function App() {
  const collection = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "blueberry", label: "Blueberry" },
    { value: "grapes", label: "Grapes", disabled: true },
    { value: "pineapple", label: "Pineapple" },
  ];

  return (
    <Select placeholder="选择器" className="min-w-50" collection={collection}>
      <div className="p-1 pb-0">
        <SelectFilter size="sm" />
      </div>
      <SelectContent className="p-1">
        <SelectEmpty />
        <SelectList />
      </SelectContent>
    </Select>
  );
}

虚拟化

使用 SelectVirtualizer 组件可以实现虚拟化

import {
  Select,
  SelectFilter,
  SelectContent,
  SelectList,
  SelectVirtualizer,
} from "@resolid/react-ui";

export default function App() {
  const collection = Array.from({ length: 1000 }, (_, i) => ({
    value: i + 1,
    label: `Item ${i + 1}`,
  }));

  const groupCollection = Array.from({ length: Math.ceil(collection.length / 10) }, (_, i) => ({
    label: `Group ${i}`,
    children: collection.slice(i * 10, (i + 1) * 10),
  }));

  return (
    <div className="flex gap-3">
      <Select placeholder="选择器" className="w-50" collection={collection}>
        <SelectContent className="max-h-60 px-1">
          <SelectVirtualizer>
            <SelectList />
          </SelectVirtualizer>
        </SelectContent>
      </Select>
      <Select placeholder="选择器" className="w-50" defaultValue={55} collection={groupCollection}>
        <SelectContent className="max-h-60 px-1">
          <SelectVirtualizer>
            <SelectList />
          </SelectVirtualizer>
        </SelectContent>
      </Select>
    </div>
  );
}

自定义渲染

import { Select, SelectContent, SelectList } from "@resolid/react-ui";
import { BrowserIcon } from "~/components/browser-icon";

export default function App() {
  const collection = [
    {
      value: "chrome",
      label: "Chrome",
      description: "Google Chrome 是一款快速、易于使用且安全的网络浏览器。",
    },
    {
      value: "firefox",
      label: "Firefox",
      description: "Firefox 是一款快速、轻量、注重隐私的浏览器,全平台可用。",
    },
    {
      value: "microsoft-edge",
      label: "Microsoft Edge",
      description: "Microsoft Edge 是 AI 驱动的浏览器。更智能的浏览方式。",
    },
    {
      value: "safari",
      label: "Safari",
      description: "Safari 是在所有 Apple 设备上体验互联网的最佳方式。",
    },
    {
      value: "opera",
      label: "Opera",
      description: "比默认浏览器更快、更安全、更智能。 功能齐全,可保护隐私、安全等。",
    },
  ];

  return (
    <Select
      placeholder="选择器"
      className="w-50"
      collection={collection}
      renderValue={(item) => {
        return (
          <div className="flex items-center gap-1">
            <BrowserIcon size="1em" name={item.value} />
            <span>{item.label}</span>
          </div>
        );
      }}
      renderItem={(item, { selected }) => {
        return (
          <div className="flex items-center gap-2">
            <div className="w-12 flex-1">
              <BrowserIcon size="2em" name={item.value} />
            </div>
            <div className="flex flex-col gap-1">
              <div>{item.label}</div>
              <div className={`text-sm ${!selected ? "text-fg-subtle" : ""}`}>
                {item.description}
              </div>
            </div>
          </div>
        );
      }}
    >
      <SelectContent className="max-w-90 p-1">
        <SelectList />
      </SelectContent>
    </Select>
  );
}

原生选择器

import { NativeSelect } from "@resolid/react-ui";

export default function App() {
  const collection = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "blueberry", label: "Blueberry" },
    { value: "grapes", label: "Grapes", disabled: true },
    { value: "pineapple", label: "Pineapple" },
  ];

  return (
    <div className="flex items-center gap-2">
      {["xs", "sm", "md", "lg", "xl"].map((size) => (
        <NativeSelect key={size} placeholder="选择器" size={size}>
          {collection.map((item) => (
            <option key={item.value} value={item.value} disabled={item.disabled}>
              {item.label}
            </option>
          ))}
        </NativeSelect>
      ))}
    </div>
  );
}

属性

Select

属性
name

字段的名称, 提交表单时使用

类型string默认值必须false
属性
multiple

是否多个值

类型boolean默认值false必须false
属性
value

受控值

类型string | number | (string | number)[] | null默认值必须false
属性
defaultValue

默认值

类型string | number | (string | number)[] | null默认值null | []必须false
属性
onChange

onChange 回调

类型(value: string | number | (string | number)[] | null) => void默认值必须false
属性
open

受控打开状态

类型boolean默认值必须false
属性
defaultOpen

初始渲染时的默认打开状态

类型boolean默认值false必须false
属性
onOpenChange

打开状态改变时调用

类型(open: boolean) => void默认值必须false
属性
valueKey

自定义 `value` 字段名

类型string默认值"value"必须false
属性
labelKey

自定义 `label` 字段名

类型string默认值"label"必须false
属性
childrenKey

自定义 `children` 字段名

类型string默认值"children"必须false
属性
disabledKey

自定义 `disabled` 字段名

类型string默认值"disabled"必须false
属性
size

大小

类型"xs" | "sm" | "md" | "lg" | "xl"默认值"md"必须false
属性
duration

动画持续时间

类型number默认值250必须false
属性
disabled

是否禁用

类型boolean默认值false必须false
属性
required

是否必需

类型boolean默认值false必须false
属性
readOnly

是否只读

类型boolean默认值false必须false
属性
invalid

是否无效

类型boolean默认值false必须false
属性
closeOnSelect

选择后关闭

类型boolean默认值true必须false
属性
collection

项目的集合

类型T[]默认值必须true
属性
placeholder

占位符

类型string默认值必须false
属性
renderGroupLabel

自定义组标签渲染

类型(group: T) => ReactNode默认值必须false
属性
renderItem

自定义项目渲染

类型(item: T, status: { active: boolean; selected: boolean; }) => ReactNode默认值必须false
属性
renderValue

自定义值渲染

类型(item: T) => ReactNode默认值必须false
属性
searchFilter

自定义过滤函数

类型(keyword: string, item: T) => boolean默认值必须false

SelectVirtualizer

属性
gap

虚拟化列表中项目之间的间距

类型number默认值必须false
属性
groupLabelHeight

分组标签的高度(以像素为单位)

类型number默认值必须false
属性
itemHeight

项目的高度(以像素为单位)

类型number默认值必须false
属性
overscan

在可见区域上方和下方渲染的项目数

类型number默认值3必须false
属性
paddingEnd

应用于虚拟器末尾的填充(以像素为单位)

类型number默认值4必须false
属性
paddingStart

应用于虚拟器开始处的填充(以像素为单位)

类型number默认值4必须false
属性
scrollPaddingEnd

滚动到元素时应用于虚拟器末尾的填充(以像素为单位)

类型number默认值4必须false
属性
scrollPaddingStart

滚动到元素时应用于虚拟器开始处的填充(以像素为单位)

类型number默认值4必须false
属性
useAnimationFrameWithResizeObserver

将 ResizeObserver 封装在 requestAnimationFrame 中,实现更顺畅的更新并减少布局抖动

类型boolean默认值必须false

建议更改此页面