Skip to content
Lenso UI

ListBox 列表框

列表框展示一组选项,并允许用户选择一个或多个。

用法

import { ListBox } from '@lenso/ui';

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 list-box-default (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { descriptionStyles } from "@lenso/tokens/description";import { labelStyles } from "@lenso/tokens/label";import { Avatar, ListBox, ListBoxItem } from "@lenso/ui";
const users = [  { key: "1", textValue: "Bob", color: "blue" },  { key: "2", textValue: "Fred", color: "green" },  { key: "3", textValue: "Martha", color: "purple" },] as const;const styles = stylex.create({  root: { width: 220 },  details: { display: "flex", flexDirection: "column" },});
export function Default() {  return (    <ListBox aria-label="Users" xstyle={styles.root} selectionMode="single">      {users.map((user) => (        <ListBoxItem key={user.key} itemKey={user.key} textValue={user.textValue}>          <Avatar size="sm">            <Avatar.Image              alt={user.textValue}              src={`https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/${user.color}.jpg`}            />            <Avatar.Fallback>{user.textValue[0]}</Avatar.Fallback>          </Avatar>          <div {...stylex.props(styles.details)}>            <span {...stylex.props(labelStyles.label)}>{user.textValue}</span>            <span {...stylex.props(descriptionStyles.description)}>              {user.textValue.toLowerCase()}@heroui.com            </span>          </div>          <ListBoxItem.Indicator />        </ListBoxItem>      ))}    </ListBox>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

组件结构

import { ListBox, Label, Description, Header } from '@lenso/ui';
export default () => (  <ListBox>    <ListBox.Item>      <Label />      <Description />      <ListBox.ItemIndicator />    </ListBox.Item>    <ListBox.Section>      <Header />      <ListBox.Item>        <Label />      </ListBox.Item>    </ListBox.Section>  </ListBox>)

示例

含禁用项

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 with-disabled-items adaptation (Apache-2.0).import { Actions } from "./actions";export function WithDisabledItems() {  return <Actions disabled />;}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

分组选项

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 with-sections adaptation (Apache-2.0).import { Actions } from "./actions";export function WithSections() {  return <Actions />;}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

多选

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 multi-select adaptation (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { UsersList, styles } from "./users";export function MultiSelect() {  return (    <div {...stylex.props(styles.surface)}>      <UsersList selectionMode="multiple" />    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

受控组件

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 controlled adaptation (Apache-2.0).import { useState } from "react";import * as stylex from "@stylexjs/stylex";import { UsersList, styles } from "./users";export function Controlled() {  const [selected, setSelected] = useState<Set<React.Key>>(new Set(["1"]));  return (    <div {...stylex.props(styles.stack)}>      <div {...stylex.props(styles.surface)}>        <UsersList          selectionMode="multiple"          selectedKeys={selected}          onSelectionChange={setSelected}          customCheck        />      </div>      <p {...stylex.props(styles.muted)}>        Selected: {selected.size ? [...selected].join(", ") : "None"}      </p>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

虚拟滚动

ListBox 通过 Virtualizer 支持虚拟化,仅渲染视口内可见行,从而高效展示大数据集。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 virtualization adaptation (Apache-2.0); native fixed-row window.import * as stylex from "@stylexjs/stylex";import { ListBox, ListBoxItem } from "@lenso/ui";import { Description, Label } from "./text";const first = [  "Emma",  "Liam",  "Olivia",  "Noah",  "Ava",  "James",  "Sophia",  "Oliver",  "Isabella",  "Lucas",  "Mia",  "Ethan",  "Charlotte",  "Mason",  "Amelia",  "Logan",  "Harper",  "Alexander",  "Ella",  "Benjamin",];const last = [  "Smith",  "Johnson",  "Williams",  "Brown",  "Jones",  "Garcia",  "Miller",  "Davis",  "Rodriguez",  "Martinez",  "Anderson",  "Taylor",  "Thomas",  "Jackson",  "White",  "Harris",  "Clark",  "Lewis",  "Robinson",  "Walker",];const users = Array.from({ length: 1000 }, (_, index) => ({  key: index + 1,  textValue: `${first[index % 20]} ${last[Math.floor(index / 20) % 20]}`,  email: `${first[index % 20]!.toLowerCase()}.${last[Math.floor(index / 20) % 20]!.toLowerCase()}@acme.com`,}));const styles = stylex.create({  list: { width: 300 },  detail: { display: "flex", flexDirection: "column" },});export function Virtualization() {  return (    <ListBox      aria-label="Virtualized list with 1000 items"      xstyle={styles.list}      items={users}      virtualized={{ rowHeight: 50, height: 400 }}    >      {(item) => (        <ListBoxItem itemKey={item.key} textValue={item.textValue}>          <div {...stylex.props(styles.detail)}>            <Label>{item.textValue}</Label>            <Description>{users[Number(item.key) - 1]!.email}</Description>          </div>          <ListBoxItem.Indicator />        </ListBoxItem>      )}    </ListBox>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义勾选图标

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 custom-check-icon adaptation (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { UsersList, styles } from "./users";export function CustomCheckIcon() {  return (    <div {...stylex.props(styles.surface)}>      <UsersList selectionMode="multiple" customCheck />    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

渲染函数

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 render-function adaptation (Apache-2.0).import { UsersList, styles } from "./users";export function RenderFunction() {  return (    <UsersList      xstyle={styles.list}      selectionMode="single"      render={(props) => <div {...props} data-custom="true" />}      renderItems    />  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义样式

Tailwind CSS

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 custom-styles adaptation (Apache-2.0).import { UsersList, styles } from "./users";export function CustomStyles() {  return (    <UsersList      aria-label="Assignee"      xstyle={styles.custom}      selectionMode="single"      customStyles      count={2}    />  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

全局 CSS

若要自定义组件类,可使用 @layer components 指令。了解更多。

@layer components {  .list-box {    @apply rounded-lg border border-border bg-surface p-2;  }
  .list-box-item {    @apply rounded px-2 py-1 cursor-pointer;  }
  .list-box-item--danger {    @apply text-danger;  }
  .list-box-item__indicator {    @apply text-accent;  }}

样式参考

HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。

CSS 类

ListBox 组件使用以下 CSS 类(查看源码样式):

基础类 [!toc]

  • .list-box - ListBox 根容器
  • .list-box-item - 单个列表项
  • .list-box-item__indicator - 选中指示图标
  • .list-box-section - 用于分组的区块容器

变体类 [!toc]

  • .list-box--default - 默认变体样式
  • .list-box--danger - 危险变体样式
  • .list-box-item--default - 列表项默认变体
  • .list-box-item--danger - 列表项危险变体

状态类 [!toc]

  • .list-box-item[data-selected="true"] - 选中状态
  • .list-box-item[data-focus-visible="true"] - 聚焦状态
  • .list-box-item[data-disabled="true"] - 禁用状态
  • .list-box-item__indicator[data-visible="true"] - 指示器可见状态

交互状态

该组件同时支持 CSS 伪类与 data 属性:

  • 悬停:列表项上 :hover 或 [data-hovered="true"]
  • 聚焦:列表项上 :focus-visible 或 [data-focus-visible="true"]
  • 已选中:列表项上 [data-selected="true"]
  • 禁用:列表项上 :disabled 或 [data-disabled="true"]

API 参考

ListBox

Prop类型默认值描述
aria-labelstring-ListBox 的无障碍标签。
aria-labelledbystring-标注 ListBox 的元素 id。
selectionMode"none" | "single" | "multiple""single"选择行为。
selectedKeysSelection-受控的选中 key。
defaultSelectedKeysSelection-初始选中 key。
onSelectionChange(keys: Selection) => void-选中变化时调用的事件处理函数。
disabledKeysIterable<Key>-禁用项的 key。
onAction(key: Key) => void-激活某项时调用的事件处理函数。
variant"default" | "danger""default"视觉变体。
classNamestring-额外的 Tailwind CSS 类。
childrenReactNode-ListBox 项与分组。
renderDOMRenderFunction<keyof React.JSX.IntrinsicElements, ListBoxRenderProps>-使用自定义渲染函数覆盖默认 DOM 元素。

ListBox.Item

Prop类型默认值描述
idKey-列表项唯一标识。
textValuestring-用于无障碍与首字母导航的文本值。
isDisabledbooleanfalse是否禁用该项。
variant"default" | "danger""default"视觉变体。
classNamestring-额外的 Tailwind CSS 类。
childrenReactNode | RenderFunction-列表项内容或渲染函数。
render(props: DetailedHTMLProps<LinkWithRequiredHref, HTMLAnchorElement> | React.JSX.IntrinsicElements[keyof React.JSX.IntrinsicElements], renderProps: ListBoxItemRenderProps) => ReactElement-使用自定义渲染函数覆盖默认 DOM 元素。

ListBox.ItemIndicator

Prop类型默认值描述
classNamestring-额外的 Tailwind CSS 类。
childrenReactNode | RenderFunction-自定义指示器内容或渲染函数。

ListBox.Section

Prop类型默认值描述
classNamestring-额外的 Tailwind CSS 类。
childrenReactNode-分组内容,包含 Header 与列表项。

RenderProps

在 ListBox.Item 或 ListBox.ItemIndicator 中使用渲染函数时,会传入以下值:

Prop类型描述
isSelectedboolean该项是否选中。
isFocusedboolean该项是否聚焦。
isDisabledboolean该项是否禁用。
isPressedboolean该项是否处于按下状态。

ListLayout

Name类型默认值描述
rowHeightnumber | undefined48行固定高度(px)。
estimatedRowHeightnumber | undefined—行高可变时的估算高度。
headingHeightnumber | undefined48分组标题固定高度(px)。
estimatedHeadingHeightnumber | undefined—标题高度可变时的估算高度。
loaderHeightnumber | undefined48加载器元素固定高度(px)。该加载器用于在根级或嵌套行/分组中渲染「加载更多」等内容。
dropIndicatorThicknessnumber | undefined2放置指示线厚度。
gapnumber | undefined0项之间的间距。
paddingnumber | undefined0列表内边距。

示例

基本用法

import { ListBox, Label, Description } from '@lenso/ui';
<ListBox aria-label="Users" selectionMode="single">  <ListBox.Item id="1" textValue="Bob">    <Label>Bob</Label>    <Description>[email protected]</Description>  </ListBox.Item>  <ListBox.Item id="2" textValue="Alice">    <Label>Alice</Label>    <Description>[email protected]</Description>  </ListBox.Item></ListBox>

分组选项

import { ListBox, Header, Separator } from '@lenso/ui';
<ListBox aria-label="Actions" selectionMode="none" onAction={(key) => console.log(key)}>  <ListBox.Section>    <Header>Actions</Header>    <ListBox.Item id="new" textValue="New file">New file</ListBox.Item>    <ListBox.Item id="edit" textValue="Edit file">Edit file</ListBox.Item>  </ListBox.Section>  <Separator />  <ListBox.Section>    <Header>Danger zone</Header>    <ListBox.Item id="delete" textValue="Delete" variant="danger">Delete</ListBox.Item>  </ListBox.Section></ListBox>

受控选择

import { ListBox, Selection } from '@lenso/ui';import { useState } from 'react';
function ControlledListBox() {  const [selected, setSelected] = useState<Selection>(new Set(["1"]));
  return (    <ListBox      aria-label="Options"      selectedKeys={selected}      selectionMode="multiple"      onSelectionChange={setSelected}    >      <ListBox.Item id="1" textValue="Option 1">Option 1</ListBox.Item>      <ListBox.Item id="2" textValue="Option 2">Option 2</ListBox.Item>      <ListBox.Item id="3" textValue="Option 3">Option 3</ListBox.Item>    </ListBox>  );}

自定义指示器

import { ListBox, ListBoxItemIndicator } from '@lenso/ui';import { Icon } from '@iconify/react';
<ListBox aria-label="Options" selectionMode="multiple">  <ListBox.Item id="1" textValue="Option 1">    Option 1    <ListBox.ItemIndicator>      {({isSelected}) =>        isSelected ? <Icon icon="gravity-ui:check" /> : null      }    </ListBox.ItemIndicator>  </ListBox.Item></ListBox>

无障碍

ListBox 组件实现 ARIA listbox 模式,并提供:

  • 完整键盘导航支持
  • 屏幕阅读器对选中变化的播报
  • 合理的焦点管理
  • 禁用状态支持
  • 首字母导航(typeahead)搜索能力

更多信息见 React Aria ListBox 文档。

相关组件