跳转到内容

标签输入 tags-input

数据录入组件。三层同源:无头内核给出解剖与状态机,Vue 组件与自定义元素只是它的两层外壳,行为完全一致。

示例

基础用法

框里打字按 Enter 落一个标签;标签由作者按当前值渲染,v-for 的 key 必须给

Vue
TypeScript

当前:Vue、TypeScript

上限与粘贴拆分

add-on-paste 让粘进来的一串按分隔符拆成多个标签;顶到 max 后再打再粘都进不去

Vue
1 / 4

就地编辑

editable 打开后双击任一标签改写它:Enter 提交、Escape 撤销,改成空白等于删掉这个标签

前端
组件库
无障碍

当前:前端、组件库、无障碍

禁用与只读

disabled 整个控件退出 Tab 序列;read-only 仍可聚焦浏览,但加不进也删不掉

Vue
Vite
Vue
Vite

形态

variant 只改控件与胶囊的颜色槽位,落标签与删标签的行为三档一致

Vue
TypeScript
Vue
TypeScript
Vue
TypeScript

语气

tone 决定用哪族颜色,与 variant 正交;这里固定 outline 只看语气的差别

标签
标签
标签
标签
标签
标签

尺寸

控件高度、胶囊与输入文字一起换档,不传 size 即默认档

Vue
TypeScript
Vue
TypeScript
Vue
TypeScript

随表单提交

写了 name 与 hidden-input 才参与提交,整份标签按断词符拼成一串;框里没内容时回车留给表单

Vue
TypeScript
表单收到:(还没提交)

入库前统一改写

给了 value 就由宿主说了算:组件只发变更意图,写回什么形状在这里定

#vue

当前:#vue

候选词一键添加

根插槽给出 addValue 与 atMax:输入框之外再开一条加标签的路,上限一样管得住

文档

外部触发的输入会话

输入部件平时收起,按「添加」才露面并聚焦;打字时给候选,选中即落标签,失焦按 blur-behavior 收尾

hi@xihan.dev

标签用对象

组件里存的是标识那一份,显示哪一份由作者定:条目文本渲染 label,提交仍按标识拼串

张三

提交出去的是标识:u-1

框里看到的是名字:张三

产物

自定义元素<xh-tags-input>
Vue 组件XhTagsInputClearTrigger XhTagsInputControl XhTagsInputHiddenInput XhTagsInputInput XhTagsInputItem XhTagsInputItemDeleteTrigger XhTagsInputItemInput XhTagsInputItemPreview XhTagsInputItemText XhTagsInputLabel XhTagsInputRoot
组合式函数useTagsInput
状态机tagsInputMachine
皮肤@xihan-ui/styles/tags-input.css

解剖

部件名即 data-part 属性值,也是皮肤的选择器。加粗的是必备部件,不渲染它组件不工作(Web Components 适配器会在诊断通道上报 wc.missing-part)。

data-scope="tags-input"root · label · control · input · item · item-preview · item-text · item-delete-trigger · item-input · clear-trigger · hidden-input

Props

属性类型必填说明
valuestring[]受控标签集合;给了就由宿主说了算,机器不自改,只发 onValueChange。
defaultValuestring[]非受控初始标签集合。
inputValuestring受控输入文本;与 value 各自独立受控。
defaultInputValuestring非受控初始输入文本。
maxnumber最多几个标签。缺省不限;写 0 表示一个也不许加。
allowOverflowboolean允许越过 max。 关(默认):顶到上限后这一次输入整体不生效,文本原样留在框里,绝不悄悄吞掉。 开:照加不误,只在 root / control 上打出 data-overflow 供样式与提示使用。
disabledboolean
readOnlyboolean
invalidboolean
namestring表单字段名;给了 hidden-input 才带 name,此时整份标签按 delimiter 拼成一串提交。
placeholderstring
delimiterstring断词符,默认逗号。打字打出它即断词成标签,粘贴时也按它拆。 显式给空串即关掉断词:此时只有 Enter 能把文本变成标签。
addOnPasteboolean粘贴时接管:按 delimiter 拆成多个标签。默认关(交给浏览器照常粘进框里)。
editableboolean允许双击标签就地改。默认关。
blurBehaviorTagsInputBlurBehavior | null焦点离开整个组件时怎么处置输入框里的残留文本。
variantControlVariant形态:outline / subtle / ghost,决定颜色怎么用。
toneTone语气:brand / neutral / success / warning / danger / info,决定用哪族颜色。
sizeSize尺寸:sm / md / lg。
translationsPartial<TagsInputTranslations>
onValueChange(details: TagsInputValueChangeDetails) => void
onInputValueChange(details: TagsInputInputValueChangeDetails) => void

状态机

状态idle · navigating · editing

事件VALUE.SET · TAG.ADD · VALUE.CLEAR · INPUT.CHANGE · INPUT.COMMIT · INPUT.BLUR · TAG.HIGHLIGHT · TAG.DELETE · TAG.EDIT · EDIT.CHANGE · EDIT.SUBMIT · EDIT.CANCEL · ITEM.FOCUS_LOST · FORM.RESET

判据canEdit · canEditTag · canDeleteWithPrev · hasHighlightTarget

connect API

useTagsInput 产出的对象。getXxxProps() 铺到对应部件的宿主元素上,其余是可读状态与操作入口。

成员类型说明
valuestring[]
countnumber标签个数,等于 value.length;作者常拿它做"3 / 5"这类计数提示。
inputValuestring
emptyboolean一个标签都没有。
disabledboolean
readOnlyboolean
invalidboolean
atMaxboolean已顶到 max:再加进不去(allowOverflow 开时只是提示,不拦)。
overflowboolean已经越过 max(只有 allowOverflow 开着才可能为真)。
highlightedValuestring | null光标停着的标签;没在标签间走时为 null。
editedValuestring | null正被就地改写的标签;不在编辑态时为 null。
canClearboolean清空按钮此刻是否可用(可编辑,且标签或输入文本至少有一样)。
setValue(next: string[]) => void整份替换,去重去空白,不受 max 约束。
addValue(next: string) => void追加一个标签,受 max 与 allowOverflow 约束。
deleteValue(value: string) => void
clear() => void
setInputValue(next: string) => void
highlight(value: string | null) => void把光标挪到某个标签上;传 null 即交回输入框。
edit(value: string) => void进入就地编辑;未开 editable 时被守卫挡下。
getRootProps() => T['element']
getLabelProps() => T['label']
getControlProps() => T['element']
getInputProps() => T['input']
getItemProps(item: TagsInputItemProps) => T['element']
getItemPreviewProps(item: TagsInputItemProps) => T['element']
getItemTextProps(item: TagsInputItemProps) => T['element']
getItemDeleteTriggerProps(item: TagsInputItemProps) => T['button']
getItemInputProps(item: TagsInputItemProps) => T['input']
getClearTriggerProps() => T['button']
getHiddenInputProps() => T['input']

键盘

规格出处:W3C APG

按键生效条件行为
Enterfocus in input, 框里有能成标签的内容, not disabled/readOnly把输入框里的文本变成标签(含 delimiter 时一次进多个);框里只有空白时不接管,Enter 留给表单提交
delimiter(默认 ,)focus in input, not disabled/readOnly断词:分隔符之前的每一段各成一个标签,最后一段留在框里接着打
Backspace输入框为空且没有标签被高亮, 至少有一个标签高亮最后一个标签(这一下不删任何东西)
Backspace输入框为空且已有标签被高亮删掉高亮的标签,光标落到前一个上;删的是第一个就交回输入框
Delete已有标签被高亮同上,删掉高亮的标签
ArrowLeftfocus in input 且光标贴着最左端(无选区), 至少有一个标签往左走一格;还没走进标签时从最后一个起步,已经在第一个就停住
ArrowRight已有标签被高亮往右走一格;走出末尾即交回输入框。光标还在框里时不接管
Home已有标签被高亮跳到第一个标签
End已有标签被高亮交回输入框
Escape已有标签被高亮取消高亮,光标交回输入框;没在标签间走时不接管该键
Enter已有标签被高亮, editable 开着就地编辑这个标签,焦点进编辑框并整段选中
Enterfocus in item-input(就地编辑中)提交改写;改成空白等于删掉这个标签,改成另一个已有标签则并成一个。焦点交回输入框
Escapefocus in item-input(就地编辑中)撤销这次改写,标签保持原样,焦点交回输入框

Released under The MIT License