• 简体中文
  • Select 选择器

    用于从下拉列表中选择一项或多项。

    基础选择

    通过 options 传入选项;placeholder 在空值时提示选择,单个选项可以禁用。

    交互预览基础选择
    basic.tsx
    import { Select } from '@sudden3/leaf-ui';
    
    const options = [
      { label: '设计工作室', value: 'design' },
      { label: '产品团队', value: 'product' },
      { label: '工程团队', value: 'engineering' },
      { label: '归档项目', value: 'archived', disabled: true },
    ];
    
    export function SelectBasic() {
      return (
        <div className="leaf-demo-stack">
          <Select aria-label="选择团队" options={options} placeholder="请选择团队" />
          <Select aria-label="默认团队" options={options} defaultValue="design" />
          <Select aria-label="禁用团队" options={options} disabled defaultValue="product" />
        </div>
      );
    }
    

    受控与校验

    value / onChange 管理选择结果,回调直接返回字符串值和选项对象。allowClear 显示清除按钮;status="error" 同时提供错误外观与 aria-invalid。

    交互预览受控与校验
    当前值:尚未选择
    controlled.tsx
    import { Select } from '@sudden3/leaf-ui';
    import { useState } from 'react';
    
    export function SelectControlled() {
      const [value, setValue] = useState('');
      return (
        <div className="leaf-demo-stack">
          <Select
            aria-label="项目可见性"
            value={value}
            placeholder="选择可见性"
            allowClear
            onChange={setValue}
            options={[
              { label: '公开', value: 'public' },
              { label: '团队', value: 'team' },
              { label: '私密', value: 'private' },
            ]}
          />
          <span className="leaf-demo-note">当前值:{value || '尚未选择'}</span>
          <Select
            aria-label="未设置团队"
            status="error"
            placeholder="请选择所属团队"
            options={[{ label: '设计团队', value: 'design' }]}
          />
        </div>
      );
    }
    

    局部主题

    通过 ConfigProvider 设置局部主题,选项浮层也会使用相同的颜色与圆角。

    交互预览局部主题与清除
    展开选项,浮层会沿用这里的紫色主题与圆角。
    theme.tsx
    import { ConfigProvider, type LeafTheme, Select } from '@sudden3/leaf-ui';
    
    const theme: LeafTheme = {
      primaryColor: '#7654c6',
      borderRadius: 6,
    };
    
    export function SelectTheme() {
      return (
        <ConfigProvider className="leaf-demo-stack" theme={theme}>
          <Select
            aria-label="主题团队"
            allowClear
            defaultValue="design"
            options={[
              { value: 'design', label: '设计工作室' },
              { value: 'product', label: '产品团队' },
            ]}
          />
          <span className="leaf-demo-note">展开选项,浮层会沿用这里的紫色主题与圆角。</span>
        </ConfigProvider>
      );
    }
    

    尺寸对齐

    交互预览尺寸对齐
    sm
    md
    lg
    control-sizes.tsx
    import { Button, type ControlSize, Input, Select } from '@sudden3/leaf-ui';
    
    export function ControlSizes() {
      return (
        <div className="leaf-demo-stack leaf-demo-stack--wide">
          {(['sm', 'md', 'lg'] as const).map((size: ControlSize) => (
            <div key={size} className="leaf-demo-control-row">
              <span className="leaf-demo-size">{size}</span>
              <Input size={size} aria-label={`${size} 搜索`} placeholder="搜索项目" />
              <Select
                size={size}
                aria-label={`${size} 状态`}
                defaultValue="all"
                options={[
                  { label: '全部状态', value: 'all' },
                  { label: '进行中', value: 'active' },
                ]}
              />
              <Button size={size}>查询</Button>
            </div>
          ))}
        </div>
      );
    }
    

    搜索与多选

    showSearch 只筛选已有选项;multiple 使用数组值并在选择后保持展开,可移除标签。

    交互预览搜索与多选
    设计
    design
    search.tsx
    import { Select, type SelectOption } from '@sudden3/leaf-ui';
    import { useState } from 'react';
    
    const options: SelectOption[] = [
      { value: 'design', label: '设计' },
      { value: 'engineering', label: '研发' },
      { value: 'marketing', label: '市场' },
    ];
    export function SelectSearch() {
      const [teams, setTeams] = useState<string[]>(['design']);
      return (
        <div className="leaf-demo-stack">
          <Select
            aria-label="搜索团队"
            showSearch
            allowClear
            options={options}
            placeholder="输入搜索团队"
          />
          <Select
            aria-label="多选团队"
            multiple
            showSearch
            allowClear
            options={options}
            value={teams}
            onChange={setTeams}
          />
          <output className="leaf-demo-note">{teams.join(', ') || '—'}</output>
        </div>
      );
    }
    

    浮层宽度与内容

    交互预览浮层宽度与内容
    Leaf Studio+1
    popup.tsx
    import { Select, type SelectOption } from '@sudden3/leaf-ui';
    
    const options: SelectOption[] = [
      { value: 'garden', label: 'Leaf Garden Design System' },
      { value: 'studio', label: 'Leaf Studio' },
      { value: 'notes', label: 'Leaf Notes' },
    ];
    export function SelectPopup() {
      return (
        <div className="leaf-demo-stack">
          <Select
            aria-label="自动浮层宽度"
            style={{ width: 180 }}
            options={options}
            defaultValue="studio"
          />
          <Select
            aria-label="固定浮层宽度"
            popupWidth={300}
            popupMaxWidth={360}
            style={{ width: 180 }}
            options={options}
            optionRender={(option) => (
              <div>
                <strong>{option.label}</strong>
                <div style={{ fontSize: 12, opacity: 0.65 }}>{option.value}</div>
              </div>
            )}
          />
          <Select
            aria-label="多选数量限制"
            multiple
            options={options}
            defaultValue={['studio', 'notes']}
            maxCount={2}
            maxTagCount={1}
            allowClear
          />
          <Select aria-label="加载选项" options={[]} loading placeholder="加载中" />
          <Select aria-label="空选项" options={[]} notFoundContent="还没有项目" />
        </div>
      );
    }
    

    Select API

    属性类型默认值说明
    size'sm' | 'md' | 'lg''md'选择器尺寸
    status'error' | 'warning'—校验状态
    optionsreadonly SelectOption[]必填选项列表
    placeholderstring'请选择'未选择时的提示文字
    value / defaultValuestring | readonly string[]''受控值 / 非受控初始值
    onChange(value: string, option?: SelectOption) => void 或 (values: string[], options: SelectOption[]) => void—返回值与选项;清除时返回空字符串和 undefined
    multiplebooleanfalse多选时值为数组,默认 []
    showSearchbooleanfalse允许输入搜索选项
    filterOptionboolean | ((query: string, option: SelectOption) => boolean)true自定义筛选,false 用于外部筛选
    onSearch(query: string) => void—搜索文字变化
    allowClearbooleanfalse展示清除按钮
    disabledbooleanfalse禁用整个选择器
    name / formstring—字段名 / 关联的表单 ID
    requiredbooleanfalse要求选择一项
    onOpenChange(open: boolean) => void—展开或收起选项面板
    refRef<HTMLInputElement>—输入框引用
    popupWidthnumber | string'auto'浮层宽度;auto 按内容扩宽,trigger 与控件等宽,也可指定像素或 CSS 长度
    popupMaxWidthnumber | string420最大宽度,仍受视口限制
    popupClassName / popupStylestring / CSSProperties—浮层样式
    loadingbooleanfalse加载提示
    notFoundContentReactNode—没有选项时的内容
    optionRender(option: SelectOption) => ReactNode—自定义选项内容
    maxCountnumber—多选数量上限,已选项可继续取消
    maxTagCountnumber—展示的标签数量,其余用数量提示

    支持 name、required、form 和非受控表单 reset;其余原生 input 属性及 aria-* 透传至输入框。className 与 style 作用于外层容器。选项 value 应唯一,不要将空字符串用作业务选项值。

    类型

    SelectProps 用于定义组件属性。单独组装选项列表时,可以使用 SelectOption:

    import type { SelectProps, SelectOption, ControlSize, ControlStatus } from '@sudden3/leaf-ui';
    
    const options: SelectOption[] = [
      { label: '设计团队', value: 'design' },
      { label: '研发团队', value: 'engineering' },
    ];

    SelectOption

    属性类型默认值说明
    valuestring必填唯一选项值,不能使用空字符串
    searchLabelstring—节点标签的搜索文字;未指定时使用 value
    labelReactNode必填选项内容,可以是文字或 React 节点
    disabledbooleanfalse禁用该选项

    使用说明

    为选择器提供 label 或 aria-label。FormData 提交选项的字符串 value,清除后为空字符串;受控组件的表单重置需同步重置自己的状态。

    Enter、空格或方向键打开面板,↑ / ↓ 移动高亮并跳过禁用选项,Home / End 跳至首尾,Enter 或空格确认。Escape 收起,Tab 继续访问后续控件。点击外部或移走焦点会收起。

    浮层随页面滚动定位,并在视口边缘避让;长列表可滚动。支持单选、多选及搜索,适用于选项数量适中的场景。

    多选清除返回 [];FormData 在同一个 name 下提交多个值,通过 formData.getAll(name) 读取。搜索文字为空时,Backspace 移除最后一个可用标签。离开控件会清空搜索文字,自由输入不会创建选项。label 为 React 节点时,用 searchLabel 指定搜索文字。ref 与原生 input 属性作用于输入框。

    控件保持页面中的布局宽度,浮层默认至少与控件等宽,并按选项内容扩宽,最多达到 popupMaxWidth。使用 popupWidth="trigger" 保持等宽,或通过 popupWidth={300} 指定宽度。内容超过最大宽度时才换行。