Semi Design TagInput 标签输入框组件完全指南:从基础用法到源码级原理
2026/9/24 15:59:47 网站建设 项目流程
  • 前端
  • UI组件
  • 设计系统

【免费下载链接】semi-design

🚀A modern, comprehensive, flexible design system and React UI library, AI-friendly built-in.🎨Provide 3000+ Design Tokens, easy to build your design system. Make Semi Design to Any Design.🧑🏻‍💻 Design to Code in one click

项目地址:https://gitcode.com/gh_mirrors/se/semi-design
点击查看免费下载

本指南以 Semi Design 官方文档(content/input/taginput/index-en-US.md)为核心,系统讲解 TagInput 标签输入框组件的能力边界与实战用法。你将掌握回车添加、分隔符批量输入、受控模式、数量/长度限制、自定义渲染与拖拽排序等全部配置方式,并通过半组件源码(packages/semi-ui/tagInputpackages/semi-foundation/tagInput)理解其底层实现原理,从而在实际业务中准确选型与排障。

TagInput 组件定位与引入方式

TagInput 是 Semi Design 输入类(Input)分类下的标签输入组件:用户敲击回车键后,输入内容会被转换为一个标签(Tag),多个标签以数组形式管理与展示。它适用于邮箱收件人、关键词、用户名单、标签筛选等需要"批量录入 + 结构化存储"的场景。

在 Semi Design 中,TagInput 由@douyinfe/semi-ui统一导出,组件入口定义在 packages/semi-ui/index.ts:

import { TagInput } from '@douyinfe/semi-ui';

从源码看,TagInput 是继承自BaseComponent的 class 组件(packages/semi-ui/tagInput/index.tsx),其逻辑层与视图层分离:交互状态由TagInputFoundation管理,UI 结构复用TagInputPopoverParagraphSortable等半组件,后续所有能力讲解都可以在 packages/semi-foundation/tagInput/foundation.ts 中找到对应实现。

基本用法:回车添加与空值过滤

最简单的用法是配合defaultValue设置初始标签、placeholder设置占位文案、onChange监听变化:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput defaultValue={['Semi', 'Design', 'Design2Code']} placeholder='Please enter...' onChange={v => console.log(v)} /> );

交互规则:敲击回车键后,输入内容成为标签;若标签内容为空字符串或纯空格,会被自动过滤。

这一规则在 foundation 的_handleAddTags中实现(foundation.ts):待添加标签经过_splitArray切分后,通过item.trim() !== ''过滤空串与纯空格,再与现有标签数组合并。

// 源码节选:packages/semi-foundation/tagInput/foundation.ts addTags = addTags.filter((item, idx) => { if (!allowDuplicates) { if (tagsArray.includes(item) || addTags.indexOf(item) !== idx) { return false; } } // Filter empty strings and pure space strings in new items return isString(item) && item.trim() !== ''; });

同时,回车键按下时会调用e.preventDefault()阻止表单提交(源码位置见 foundation.ts),避免在 Form 中使用时误触提交,这一点在使用时无需额外处理。

批量添加:用 separator 分隔符一次输入多个标签

separator用于设置批量输入的分隔符,默认值为英文逗号,。支持单个分隔符(string)和多个分隔符(string[])两种格式:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <> <TagInput separator='-' placeholder='Use `-` for batch input' onChange={v => console.log(v)} /> <br/><br/> <TagInput separator={['-', '/', '|', '++']} placeholder='Support multiple separators for batch input' onChange={v => console.log(v)} /> </> );

默认separator: ','在组件defaultProps中定义(index.tsx)。底层切分逻辑位于 packages/semi-foundation/tagInput/utils/getSplitedArray.ts:

  • 分隔符为string时,直接调用originString.split(separator)
  • 分隔符为string[]时,先取第一个分隔符作为临时分隔符,依次将其他分隔符替换为临时分隔符后再统一切分,从而支持任意多个分隔符并存;
  • 分隔符为null时,整个输入串作为单个标签(测试用例 "when separator is null" 验证了该行为,见 tagInput.test.js);
  • 分隔符甚至可以是数字类型,测试中separator={1}可将'semi1design'切分为['semi', 'design']

自定义切分函数 split(v2.90.0+)

从 2.90.0 版本起,可以通过split属性自定义分隔符处理函数,签名与内置getSplitedArray一致:

属性说明类型
split自定义分隔符处理函数(value: string, separator: string) => string[]

在 foundation 的_splitArray中(foundation.ts),若传入split函数则优先使用自定义实现,否则回退到getSplitedArray默认实现。这为"分隔符带转义"“按正则切分”等特殊场景提供了扩展入口。

批量删除:showClear 一键清空

showClear用于控制是否显示一键清空按钮。开启后,鼠标悬浮时输入框右侧会出现清空图标,点击可同时删除全部标签与输入框内容:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput showClear defaultValue={['Semi', 'Design2Code']} placeholder='Please enter...' onChange={v => console.log(v)} /> );

清空按钮的显隐逻辑在renderClearBtn中(index.tsx):仅在showClear为 true、且 hover 状态下、且(有输入或存在标签)时可见,禁用状态下同样隐藏。清空动作在 foundation 的handleClearBtn中执行(foundation.ts):标签数组置空并触发onChange([]),输入内容清空,同时e.stopPropagation()防止事件冒泡到外层。

禁用与尺寸

disabled使组件只读、禁用一切交互;size控制组件尺寸,可选smalldefaultlarge,默认defaultSIZE_SET定义于 constants.ts):

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput disabled showClear defaultValue={['Semi', 'Design2Code']} placeholder='Please enter...' /> );
import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <> <TagInput size='small' placeholder='small'/> <br/><br/> <TagInput placeholder='default'/> <br/><br/> <TagInput size='large' placeholder='large'/> </> );

尺寸不仅影响整体高度,还会联动内部标签大小:renderTagsize === 'small'时内部 Tag 使用small尺寸,否则使用large尺寸(index.tsx)。尺寸对应的圆角、高度、间距等由设计变量控制,详见 packages/semi-foundation/tagInput/variables.scss。

校验状态样式:validateStatus

validateStatus仅影响样式表现(背景色、描边色等),不影响实际校验逻辑,可选值defaultwarningerror

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <> <TagInput placeholder='default'/> <br/><br/> <TagInput placeholder='warning' validateStatus='warning'/> <br/><br/> <TagInput placeholder='error' validateStatus='error'/> </> );

样式映射在render()的 className 拼接中(index.tsx),分别追加semi-tagInput-warningsemi-tagInput-error。warning / error 态的完整背景色、描边色、hover 与 focus 色板定义在 variables.scss。此外,validateStatus='error'时还会自动设置aria-invalid={true}(见 index.tsx),测试用例对此有明确断言(tagInput.test.js)。

前缀与后缀:prefix / suffix

通过prefix传入输入框前缀、suffix传入后缀,支持文本或任意 ReactNode:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; import { IconVigoLogo, IconGift } from '@douyinfe/semi-icons'; () => ( <> <TagInput prefix={<IconVigoLogo />} showClear/> <br/><br/> <TagInput prefix="Prefix" showClear/> <br/><br/> <TagInput suffix={<IconGift />}/> <br/><br/> <TagInput suffix="Suffix" showClear/> </> );

间距规则:当prefix/suffix传入的是 string 或半图标(Semi Icon)时,自动带上左右间隔(对应-prefix-text-prefix-icon-suffix-text-suffix-icon样式类,见 index.tsx);若为自定义 ReactNode,左右间隔为 0,需要可在传入的 ReactNode 内自行设置。点击 prefix / suffix 区域会通过handleClickPrefixOrSuffix将焦点移入输入框(foundation.ts)。prefix / suffix 的水平外边距由$spacing-tagInput_prefix_suffix-marginX定义(variables.scss)。

失焦自动创建标签:addOnBlur

addOnBlur用于设置 blur 事件触发时,是否将当前输入值自动创建为标签:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput addOnBlur={true} defaultValue={['Semi', 'Design', 'Design2Code']} placeholder='Please enter...' onChange={v => console.log(v)} /> );

实现位于 foundation 的handleInputBlur(foundation.ts):当addOnBlur === true时先调用_handleAddTags(e)将输入内容转为标签,再重置聚焦状态并触发onBlur回调。注意该行为会复用与回车添加完全相同的过滤、去重与 max 限制逻辑。

重复标签控制:allowDuplicates

allowDuplicates控制是否允许创建相同标签,默认true

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput allowDuplicates={false} defaultValue={['Semi', 'Design', 'Design2Code']} placeholder='Please enter...' onChange={v => console.log(v)} /> );

过滤逻辑在_handleAddTags中(foundation.ts):当allowDuplicates === false时,既会过滤与现有tagsArray重复的项,也会过滤同批输入中自身重复的项(addTags.indexOf(item) !== idx)。测试用例分别验证了allowDuplicates: true时可添加重复标签、false时不可(tagInput.test.js)。

输入限制:max 与 maxLength

两个维度限制输入:

  • max:限制标签总数量,超出后触发onExceed()回调,超出部分不会加入;
  • maxLength:限制单个标签的最大长度,超出后触发onInputExceed()回调,且输入内容会被拦截。
import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <> <TagInput max={3} placeholder='max = 3' onChange={v => console.log(v)} onExceed={v => { Toast.warning('Exceeds max'); console.log(v); }} /> <TagInput maxLength={5} placeholder='maxLength = 5' style={{ marginTop: 12 }} onChange={v => console.log(v)} onInputExceed={v => { Toast.warning('Exceeds maxLength'); console.log(v); }} /> </> );

两个限制的回调参数类型不同:onExceed回调收到的是超出后的完整标签数组string[]onInputExceed回调收到的是触发超长的输入串string

实现细节:

  • max的拦截在_handleAddTags中(foundation.ts):合并后若超过max,触发onExceed,再通过slice(0, max)截断新标签列表;
  • maxLength的拦截在_checkInputChangeValid中(foundation.ts):按分隔符切分后逐段比较长度,输入增长且超过maxLength时拒绝本次变更并触发onInputExceed。测试用例验证了输入'tikt'(maxLength=3)时输入框值停留在'tik'(tagInput.test.js)。

输入法(IME)组合输入的处理

值得注意:当配置了maxLength时,组件通过handleInputCompositionStart/handleInputCompositionEnd处理中文等输入法组合输入(foundation.ts)。组合输入过程中(entering === true)不校验长度,直接更新inputValue(此时内容为拼音等中间态);组合结束后在handleInputCompositionEnd中统一校验,超长部分会被截断为maxLength长度。源码注释特别说明:之所以在组合结束事件中更新值,是因为 Firefox 下组合结束后 onChange 可能不再触发。这正是"中文输入场景下 maxLength 生效但输入体验不被打断"的原因。

限制标签展示数量:maxTagCount 与 +N

maxTagCount限制渲染出来的标签数量,超出部分以+N形式展示;showRestTagsPopover(默认true)控制 hover +N 时是否通过 Popover 展示剩余标签,restTagsPopoverProps可配置该 Popover 的属性(如方向、zIndex、trigger):

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput maxTagCount={2} showRestTagsPopover={true} restTagsPopoverProps={{ position: 'top' }} defaultValue={['Semi', 'Design', 'Design2Code']} /> );

实现位于renderTags(index.tsx):当maxTagCount < allTags.length时,tags截取前 N 个,restTags保存剩余项,渲染+N节点;showRestTagsPopover为 true 时用Popover包裹+N,并将restTagsPopoverProps展开合并(默认position="top"trigger="hover"showArrow)。

相关属性:showContentTooltip 与 expandRestTagsOnClick

  • showContentTooltip(默认true):单个标签过长发生截断时,hover 标签是否通过 Tooltip 展示全部内容。支持布尔值或对象{ type: 'tooltip' | 'popover', opts: object },其中opts为透传给浮层组件的属性。在renderTag中通过Paragraphellipsis={{ showTooltip: showContentTooltip, rows: 1 }}生效(index.tsx)。
  • expandRestTagsOnClick(默认true,v2.17.0+):在不可拖拽的情况下,点击 TagInput 后是否展开多余的标签。当!active || !expandRestTagsOnClick时保持折叠,active为 true(组件被点击激活)且expandRestTagsOnClick为 true 时全部展开(index.tsx)。

受控模式:标签受控与输入受控

标签受控:value + onChange

使用value设置标签数组,配合onChange实现完全受控:

import React, { useCallback, useState } from 'react'; import { TagInput } from '@douyinfe/semi-ui'; function TagInputDemo() { const [value, setValue] = useState(['semi']); const handleChange = useCallback(v => setValue(v), []); return <TagInput value={value} onChange={handleChange} />; }

受控与非受控的判定逻辑在 foundation 的_isControlledComponent中体现:_onAdd_onRemovehandleSortEnd内部均先判断是否受控,受控时不直接改写内部tagsArray,只通知onChange,由外部驱动 value 更新(foundation.ts)。getDerivedStateFromProps(index.tsx)保证传入value时以 props 为准;若传入value={null}value={undefined},标签数组会被清空(测试用例见 tagInput.test.js)。

输入受控:inputValue + onInputChange

使用inputValue控制输入框内容,配合onInputChange实现输入受控:

import React, { useCallback, useState } from 'react'; import { TagInput } from '@douyinfe/semi-ui'; function TagInputDemo() { const [value, setValue] = useState('semi'); const handleInputChange = useCallback((v, e) => setValue(v), []); return <TagInput inputValue={value} onInputChange={handleInputChange} />; }

onInputChange签名(value: string, e: React.KeyboardEvent) => voidgetDerivedStateFromPropsisString(inputValue)时以 props 为准(index.tsx)。

回调函数全集

onChange之外,TagInput 还提供颗粒度更细的增删回调:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput defaultValue={['Semi', 'Design2Code']} showClear onFocus={e =>{console.log(`onFocus`);}} onBlur={e=>{console.log(`onBlur`);}} onChange={tag=>{console.log(`onChange :${tag}`);}} onAdd={tag=>{console.log(`onAdd :${tag}`);}} onRemove={(v, i)=>{console.log(`onRemove :${v}, index:${i}`);}} onInputChange={(input, e)=>{console.log(`onInputChange :${input}`);}} /> );

各回调触发时机与数据(对照 foundation.ts):

回调触发时机参数
onAdd新增标签时(回车/失焦/批量添加成功)(addedValue: string[])本次新增的标签数组
onRemove移除标签时(点关闭/退格键)(removedValue: string, idx: number)被移除的标签值与下标
onChange标签数组任何变化(增、删、清空、排序)(value: string[])最新标签数组
onInputChange输入框内容变化(value: string, e)当前输入串与事件
onFocus/onBlur输入框聚焦/失焦(e: React.MouseEvent)
onKeyDown键盘按下(v2.1.0+)(e: React.KeyboardEvent)
onExceed/onInputExceed超出 max / maxLength见上文"输入限制"

一个容易混淆的点:onRemove的回调参数是"被移除的单值 + 下标",而onAdd的参数是"本次新增的数组"。测试用例对onAddonRemove的调用次数与参数均有断言(tagInput.test.js)。

焦点管理:focus() 与 blur()

TagInput 通过 ref 暴露focus()blur()两个实例方法,用于外部接管焦点:

import React, { useCallback, useRef } from 'react'; import { TagInput, Button } from '@douyinfe/semi-ui'; function TagInputDemo() { const ref = useRef(); const handleTagInputFocus = useCallback(() => { ref.current && ref.current.focus(); }, []); return ( <> <TagInput defaultValue={['Semi', 'Design2Code']} ref={ref} /> <Button style={{ marginTop: 10 }} onClick={handleTagInputFocus}> focus </Button> </> ); }

focus()实现(index.tsx)会调用inputRef.current.focus({ preventScroll }),并在非禁用状态下激活组件(注册点击外部关闭 handler,使拖拽/展开等激活态生效);blur()(index.tsx)则移出焦点并注销点击外部 handler。preventScroll属性(默认false)可控制focus()时浏览器是否滚动文档以显示新聚焦元素,它作用于组件内部(含 autoFocus、focus 方法、prefix/suffix 点击聚焦)的 focus 调用,但不影响用户自行传入元素的 focus 行为。

自定义标签渲染:renderTagItem

renderTagItem可完全自定义标签节点的渲染,签名renderTagItem(value: string, index: number, onClose: function) => React.ReactNode,第三个参数onClose自 v2.23.0 起提供,可用于在自定义节点中接入关闭逻辑。典型场景是"头像 + 文本 + 关闭图标"的组合标签:

import React, { useCallback, useMemo, useState } from 'react'; import { TagInput, Avatar } from '@douyinfe/semi-ui'; import { IconClose } from '@douyinfe/semi-ui-icons'; function CustomRender() { const [value, setValue] = useState(['xiakeman']); const list = useMemo(() => ([ { "name": "xiakeman", "avatar": "https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/avatarDemo.jpeg" }, { "name": "shenyue", "avatar": "https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg" }, { "name": "quchenyi", "avatar": "https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/dbf7351bb779433d17c4f50478cf42f7.jpg" }, { "name": "wenjiamao", "avatar": "https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/7abf810ff060ac3387bd027ead92c4e0.jpg" }, ]), []); const mapList = useMemo(() => new Map(list.map(item => [item.name, item])), [list]); const renderTagItem = useCallback((value, index, onClose) => { const data = mapList.get(value); return ( <div key={index} style={{ display: 'flex', alignItems: 'center', fontSize: 14, marginRight: 10 }} > <Avatar alt='avatar' src={data ? data.avatar : 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/dy.png'} size="extra-small" /> <span style={{ marginLeft: 8 }}> {`${value}@semi.com`} </span> <IconClose onClick={onClose} /> </div> ); }, [mapList]); return ( <TagInput value={value} onChange={setValue} renderTagItem={renderTagItem} /> ); }

实现要点(index.tsx):传入renderTagItem后,内部不再渲染默认 Tag,而是直接调用自定义渲染函数;组件会把onClose包装为"调用handleTagClose(index)且阻止 Tag 内部setVisible(false)默认行为"的闭包,因此自定义节点内的关闭按钮也能正确联动标签删除(index.tsx)。启用拖拽时,自定义节点前会额外渲染拖拽手柄(见下文)。

拖拽排序:draggable

draggable设为true(v2.17.0+)可开启拖拽排序。需要注意:拖拽排序模式下不允许添加相同 Tag,因此必须同时将allowDuplicates设为false。交互上,点击 TagInput 后 Tag 可拖拽;点击 TagInput 外任意区域后 Tag 不可拖拽:

import React from 'react'; import { TagInput } from '@douyinfe/semi-ui'; () => ( <TagInput draggable allowDuplicates={false} defaultValue={['Semi', 'Design', 'Design2Code']} placeholder='please enter...' onChange={v => console.log(v)} /> );

源码层面,拖拽由_sortable/Sortable组件承载(index.tsx):组件处于active(点击激活)状态且draggable为 true 时,将标签数组渲染为可排序列表,并注入拖拽手柄(IconHandle);排序结束时调用 foundation 的handleSortEnd(foundation.ts),通过arrayMove计算新数组并触发onChange。拖拽中的元素 z-index 为 2000($z-tagInput_drag_item_move,见 variables.scss)。

API 参考(完整属性表)

以下为 TagInput 全部 Props,与文档 API 表一一对应(类型定义见 index.tsx):

属性说明类型默认值版本
addOnBlur是否在 blur 事件触发时将当前输入值自动创建为标签booleanfalse-
allowDuplicates是否允许添加相同标签booleantrue-
autoFocus初始渲染时是否自动聚焦booleanfalse-
className样式类名string--
defaultValue默认标签值string[]--
disabled只读,禁用交互booleanfalse-
inputValue受控输入值string--
maxLength单个标签的最大长度number--
max允许的标签最大数量number--
maxTagCount标签最大展示数量,超出以 +N 展示number--
showRestTagsPopover超出 maxTagCount 后 hover +N 是否通过 Popover 显示剩余内容booleantrue-
restTagsPopoverPropsPopover 配置属性(方向、zIndex、trigger 等)PopoverProps{}-
showContentTooltip标签过长截断时 hover 是否通过 Tooltip 显示全部内容;传对象时可指定浮层组件类型与透传属性boolean | {type: 'tooltip' | 'popover', opts: object}true-
placeholder占位文案string--
prefix前缀(文本或 ReactNode)ReactNode--
preventScroll指示浏览器是否滚动文档以显示新聚焦元素,作用于组件内部 focus 方法boolean--
renderTagItem自定义标签渲染,onClose 参数自 2.23.0 提供(value: string, index: number, onClose: function) => React.ReactNode--
separator批量输入分隔符string | string[],-
showClear是否显示一键清空按钮booleanfalse-
size尺寸:small / large / defaultstringdefault-
split自定义分隔符处理函数(value: string, separator: string) => string[]-2.90.0
style内联样式React.CSSProperties--
suffix后缀(文本或 ReactNode)ReactNode--
validateStatus校验状态样式:default / warning / errorstringdefault-
value受控标签值string[] | undefined--
draggable是否可拖拽排序booleanfalse2.17.0
expandRestTagsOnClick不可拖拽时,点击 TagInput 后是否展开多余标签booleantrue2.17.0
onAdd添加标签时的回调(addedValue: string[]) => void--
onBlur输入框失焦回调(e: React.MouseEvent) => void--
onChange标签变化回调(value: string[]) => void--
onExceed超过 max 时的回调(value: string[]) => void--
onFocus输入框聚焦回调(e: React.MouseEvent) => void--
onInputChange输入框内容变化回调(value: string, e: React.KeyboardEvent) => void--
onInputExceed超过 maxLength 时的回调(value: string) => void--
onKeyDownkeydown 回调(e: React.KeyboardEvent) => void-2.1.0
onRemove移除标签时的回调(removedValue: string, idx: number) => void--

Methods:ref 实例方法

绑定在组件实例上、可通过 ref 调用的方法:

名称描述版本
blur()移出焦点-
focus()获取焦点-

用法见上文"焦点管理"一节;focus()blur()的底层实现位于 index.tsx。

无障碍(Accessibility)

TagInput 内置了完整的 ARIA 支持(对应源码 index.tsx 与renderClearBtn中的按钮实现):

  • 支持传入aria-label表示该 TagInput 的作用;
  • 组件根节点依据disabledvalidateStatus分别设置aria-disabledaria-invalid(error 时为 true);
  • 输入框与清空按钮均具有aria-label表明元素作用(输入框为"input value",清空按钮为"Clear TagInput value");
  • 清空按钮以role="button"+tabIndex={0}呈现,并支持键盘 Enter 触发清空(handleClearEnterPress,见 foundation.ts);
  • 默认渲染的每个 Tag 也带有语义化aria-label(如"Closable Tag: xxx",见 index.tsx)。

设计变量(Design Tokens)

TagInput 的视觉样式全部通过设计变量(Design Token)驱动,与 Semi Design 主题体系打通,可在自定义主题时统一调整。以 packages/semi-foundation/tagInput/variables.scss 为例,主要分类包括:

  • 颜色:默认/悬浮/聚焦态背景色(--semi-color-fill-0/1--semi-color-focus-border)、warning/error 态背景与描边(--semi-color-warning-*--semi-color-danger-*)、禁用态文字与背景(--semi-color-disabled-*)、prefix/suffix 文字色、拖拽元素竖线色等;
  • 间距与尺寸:small/default/large 三档高度与标签外边距($spacing-tagInput_small-Y等)、prefix/suffix 水平外边距、拖拽手柄右外边距;
  • 圆角与描边$radius-tagInput与三态描边宽度;
  • 层级:拖拽中元素的z-index(2000)。

这些 token 与DesignToken文档区块对应,开发者可在 Semi Design 主题定制体系中覆盖同名变量实现全局或局部换肤。

附:源码研读索引

若希望进一步深入 TagInput 的实现细节,可从以下文件入手:

  • 组件视图层:packages/semi-ui/tagInput/index.tsx(Props/State 定义、渲染、ref 方法)
  • 逻辑层:packages/semi-foundation/tagInput/foundation.ts(添加/删除/限制/输入法/拖拽排序全部交互逻辑)
  • 分隔符切分工具:packages/semi-foundation/tagInput/utils/getSplitedArray.ts
  • 常量定义:packages/semi-foundation/tagInput/constants.ts(尺寸与状态枚举)
  • 样式变量:packages/semi-foundation/tagInput/variables.scss
  • 单元测试:packages/semi-ui/tagInput/test/tagInput.test.js(覆盖受控、分隔符、限制、回调、拖拽、ARIA 等 40+ 场景)
  • 中英文文档:content/input/taginput/index.md、content/input/taginput/index-en-US.md

综上,TagInput 的核心设计是"逻辑层(foundation)与视图层(semi-ui)分离":所有输入校验、过滤、去重、截断规则都集中在 foundation 中,视图层只负责渲染与事件转发。理解这一架构后,无论是排查"为什么标签没加上"还是扩展自定义能力,都能快速定位到 foundation.ts 中对应的处理函数。

  • 前端
  • UI组件
  • 设计系统

【免费下载链接】semi-design

🚀A modern, comprehensive, flexible design system and React UI library, AI-friendly built-in.🎨Provide 3000+ Design Tokens, easy to build your design system. Make Semi Design to Any Design.🧑🏻‍💻 Design to Code in one click

项目地址:https://gitcode.com/gh_mirrors/se/semi-design
点击查看免费下载

相关推荐

上一篇:物理信息神经网络完整指南:5大优势让你快速掌握微分方程求解新方法
下一篇:微信聊天记录终极指南:如何从安卓设备解密和导出完整历史

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询