标签输入 · Tokenizer
标签输入用于表单输入场景。下面的官方示例展示原生用法与状态,属性名保持上游 API。
安装与前置条件
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0
需要 React 19+,按顺序导入基础 CSS 和主题,并设置 Theme Provider。参见开始使用。
示例与使用方式
- 标签输入 · 综合展示 1:首先体验这个示例,再查看代码理解组件的组合方式。
- 标签输入 · 交互示例 2:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 标签输入 · 交互示例 3:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 标签输入 · 交互示例 4:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 标签输入 · 交互示例 5:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 标签输入 · 交互示例 6:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 标签输入 · 溢出处理 7:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 标签输入 · 多种状态 8:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
API 与上游详细参考
优先使用 0.7.1 官方中文说明;上游尚未提供中文的条目保留英文。属性名、类型及默认值保持原生 API,不把示例状态名称当成组件属性。
Tokenizer
Tokenizer is a multi-select input that lets users search, select, and manage multiple items displayed as removable chips. Use it when users need to build a set of selections from a searchable data source, like adding team members, applying tags, or choosing filters.
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| label * | string | 输入框的无障碍标签。 | |
| searchSource * | SearchSource<T> | 提供搜索和引导方法的数据源,用于填充下拉列表。 | |
| value * | T[] | 当前已选项目的数组。 | |
| onChange * | (items: T[], change: TokenizerChange<T>) => void | 选择变更时调用。change 参数包含受影响的项目和类型('add' | 'create' | 'remove' | 'reorder')。 | |
| placeholder | string | 输入框占位文本。仅在未选择任何标记时显示。 | |
| maxEntries | number | 允许的最大选择数量。达到限制时输入框会隐藏。 | |
| hasClear | boolean | false | 显示全部清除按钮,用于批量移除所有标记。 |
| renderToken | (item: T, onRemove: () => void) => ReactNode | 已选标记的自定义渲染函数。默认渲染带有 label 和 onRemove 的 Token。 | |
| renderItem | (item: T) => ReactNode | 下拉列表项的自定义渲染函数。默认渲染 TypeaheadItem。 | |
| isDisabled | boolean | false | 禁用输入框和所有标记交互。 |
| htmlName | string | 用于表单提交的 HTML name 属性。为每个已选项目的 id 渲染一个隐藏输入。 | |
| disabledMessage | string | Explains why the tokenizer is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the input focusable via aria-disabled (input stays blocked). Use this instead of wrapping a disabled Tokenizer in Tooltip. Disabled controls swallow the hover events an external Tooltip needs. | |
| status | {type: 'warning' | 'error' | 'success', message?: string} | 验证状态对象,包含类型和消息,用于错误/警告/成功状态。 | |
| statusVariant | 'attached' | 'detached' | 'tooltip' | 'attached' | 状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距;tooltip 在状态图标的提示气泡中显示消息。 |
| isLabelHidden | boolean | false | 视觉隐藏标签,同时保持其可访问性。 |
| description | string | 显示在标签下方的辅助文本。 | |
| isRequired | boolean | false | 将字段标记为必填。 |
| isOptional | boolean | false | 在标签上显示可选指示器。 |
| labelTooltip | string | 标签上显示的工具提示文本。 | |
| hasEntriesOnFocus | boolean | false | 聚焦时在输入前显示引导结果。 |
| maxMenuItems | number | 10 | 下拉列表显示的最大搜索结果数。“创建 ...”条目会在此之外额外提供,因此菜单可能比该数量多显示一项。 |
| menuWidth | number | 下拉菜单的固定像素宽度。菜单不会小于其锚点宽度。 | |
| minQueryLength | number | 1 | 查询搜索源前的最小查询长度。低于该长度不会发起搜索,菜单保持关闭;但设置 hasCreate 时仍会提供“创建 ...”条目——该条目由输入的文本推导而来,并非通过搜索获取。 |
| emptySearchText | ReactNode | 'No results found' | 查询无匹配结果时显示的内容。接受 ReactNode,因此可在无结果处放置链接或创建入口。会从 DOM 读取其渲染出的文本在礼貌性实时区域中播报;aria-hidden 的部分两处都不包含,不渲染任何文本的内容则不会播报。null 与 undefined 同样视为未提供,将回退到默认值;若要不渲染任何内容,请传入空字符串。 |
| hasAutoFocus | boolean | false | 挂载时自动聚焦输入框。 |
| size | 'sm' | 'md' | 'lg' | 'md' | 输入框和标记的尺寸。 |
| debounceMs | number | 150 | 触发搜索前的防抖延迟(毫秒)。同步数据源设置为 0。 |
| hasCreate | boolean | false | Allow users to create new tokens from free-text input. When true, a "Create" option appears in the dropdown for typed text that doesn't match existing results. The onChange change type is 'create' for these items. |
| onChangeQuery | (query: string) => void | 搜索查询文本变更时触发的回调。 | |
| startIcon | ReactNode | IconType | 在输入框开头(token 之前)显示的图标。接受语义图标名称、SVG 图标组件或直接传入 ReactNode。 | |
| endContent | ReactNode | 在输入行末尾显示的内容。适用于按钮、结果计数或其他控件。 | |
| handleRef | React.Ref<TokenizerHandle> | 用于 focus() 和 blur() 控制的命令式句柄。 | |
| width | SizeValue | Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned. | |
| tokenOverflowBehavior | 'none' | 'unfocusedInline' | 'unfocusedLayer' | 'none' | Controls how tokens overflow when the container is too narrow. |
| onFocus | (e: FocusEvent<HTMLInputElement>) => void | Fires when focus enters the tokenizer input. | |
| onBlur | (e: FocusEvent<HTMLInputElement>) => void | Fires when focus leaves the tokenizer input. | |
| containerXstyle | StyleXStyles | 字段容器(标签、控件和状态整体)的 StyleX 样式。在 InputGroup 内(请改为设置 InputGroup 的样式)或 horizontal-labels FormLayout 中无效。不接受根级 xstyle、className 和 style。 | |
| containerClassName | string | 字段容器的类名,作用目标同 containerXstyle。 | |
| containerStyle | CSSProperties | 字段容器的内联样式,作用目标同 containerXstyle。 | |
| controlXstyle | StyleXStyles | 可视控件框的 StyleX 样式:绘制边框和背景并包含图标与尾部控件的元素,而非原生输入元素。 | |
| controlClassName | string | 可视控件框的类名。 | |
| controlStyle | CSSProperties | 可视控件框的内联样式。 |
使用建议
- Write a placeholder that tells users what they can search for, such as "Search people..." or "Add tags...", so the input is not a blank mystery.
- Set maxEntries when the number of selections should be bounded, like limiting a review to 5 approvers.
- Use hasCreate for free-form tagging where users need to enter values that do not exist in the search source.
- Show validation status with the status prop so users know immediately when a selection is missing or invalid.
- 避免:Don't use Tokenizer for single-item selection; use Typeahead instead. Tokenizer is for building sets of two or more items.
- 避免:Avoid applying custom colors to individual tokens inside a Tokenizer; use the default token style for visual consistency across the set.
- 避免:Don't hide the label; every Tokenizer needs a visible label so users understand what they are selecting. Use isLabelHidden only when surrounding context makes the purpose obvious.
- 避免:Wrap a disabled Tokenizer in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.
主题 API
{
"targets": [
{
"className": "astryx-tokenizer",
"visualProps": [
"size",
"status"
],
"states": [
"disabled"
]
}
]
}
组件结构
- Label: The visible text above the input describing what the user is selecting. Also used as the accessible name.
- Token chips: Removable chips representing each selected item. Each chip shows a label and a remove button.
- Search input: The text input where users type to search the data source. Hides when maxEntries is reached.
- Dropdown menu: The search results list that appears below the input as the user types.
- Spinner: Loading indicator shown at the end of the field while a search is in flight.
- End content: A trailing slot after the input for action buttons, counts, or other controls.
- Clear button: A button that removes all selected tokens at once. Shown when hasClear is true and tokens are present.
完整示例的额外依赖
部分示例使用独立图标包。示例清单中的每条安装命令包含该示例实际需要的依赖;若要运行本页全部示例,还需安装:
npm install @heroicons/react@2.2.0