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

演示

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 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>
    <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.join(", ")}</p>
      <Select className={"w-50"} value={value} onChange={setValue} collection={collection}>
        <SelectContent className={"p-1"}>
          <SelectList></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 defaultValue={"blueberry"} className={"w-50"} collection={collection}>
        <SelectContent className={"p-1"}>
          <SelectList></SelectList>
        </SelectContent>
      </Select>
      <Select
        multiple
        defaultValue={["apple", "pineapple"]}
        className={"min-w-50"}
        collection={collection}
      >
        <SelectContent className={"p-1"}>
          <SelectList></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 className={"min-w-50"} multiple collection={collection}>
      <SelectContent className={"p-1"}>
        <SelectList></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 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 / 20) }, (_, i) => ({
    label: `Group ${i + 1}`,
    children: collection.slice(i * 20, (i + 1) * 20),
  }));

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

自定义渲染

import { Select, SelectFilter, 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
      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

属性
duration

动画持续时间

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

是否多选

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

项目的集合

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

自定义 `value` 字段名

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

自定义 `label` 字段名

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

自定义 `disabled` 字段名

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

自定义 `children` 字段名

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

自定义过滤函数

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

自定义项目渲染

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

自定义组标签渲染

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

大小

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

自定义值渲染

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

占位符

类型string默认值-必须false
属性
closeOnSelect

选择后关闭

类型boolean默认值true必须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
属性
name

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

类型string默认值-必须false
属性
open

受控打开状态

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

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

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

打开状态改变时调用

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

是否禁用

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

是否必需

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

是否只读

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

是否无效

类型boolean默认值false必须false

SelectVirtualizer

属性
itemHeight

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

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

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

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

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

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

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

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

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

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

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

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

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

类型number默认值17必须false
属性
gap

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

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

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

类型boolean默认值false必须false

建议更改此页面