Skip to content

Label 标签文字 ​

表单项的标签:14/20、中等字重、标题色。for 指向控件的 id,点标签时把焦点交给控件,勾选类则直接切换。

基础用法

for 指向控件的 id:点标签时文本类控件获得焦点,勾选类直接切换;标签文字同时成为控件的可访问名,控件上不必再写 aria-label。

<pt-label for="demo-label-email" required>邮箱地址</pt-label>
<pt-input id="demo-label-email" type="email" placeholder="name@example.com" required></pt-input>
<pt-label for="demo-label-agree">同意服务条款</pt-label>
<pt-checkbox id="demo-label-agree"></pt-checkbox>
必填与禁用

必填星号只是视觉提示(对读屏隐藏),必填语义写在控件的 required 上;禁用时半透明,点击不再转交。

<pt-label required>必填</pt-label>
<pt-label disabled>禁用</pt-label>

点标签发生什么 ​

for 的写法与原生 <label for> 相同。在 React 里属性名是 htmlFor(for 是 JS 保留字), 原生 HTML、Vue 与 Angular 模板里静态值照常写 for,要绑定变量时用 property 名(:html-for / [htmlFor])。

目标在标签所在的根里按 id 查找:标签在 document 里就找 document,被放进某个组件的影子树时就在那棵影子树里找。 找到之后按控件类型分两种处理,与浏览器对原生 label 的处理一致:

目标行为
pt-checkbox、pt-switch、pt-button;原生 checkbox / radio / button / file…调用目标的 click():勾选类切换并发 ptChange,按钮类触发点击
其它(pt-input、pt-textarea、pt-select、原生文本框……)调用目标的 focus():我们的控件都是 delegatesFocus 宿主,焦点进入内部

下列情况不转交:没有 for、for 为空或找不到目标;disabled;点在标签里的链接或按钮上(那是在用它们); 目标本身就包在标签里(这次点击已经落在它身上了)。

标签不可聚焦,没有键盘交互。双击标签不会选中文字。

无障碍 ​

标签文字就是控件的可访问名,控件上不用再写 aria-label。

原生 <label for> 做不到这一点:它只关联同一棵树里的原生可标注元素,而我们控件真正获得焦点的元素 (<input>、role="checkbox" 的方框……)在各自的影子树里。pt-label 通过内部的 utils/aria-link 把自己关联到那个元素上,下列控件都已接入:

控件名字落在哪
pt-input / pt-textarea影子树里的 <input> / <textarea>
pt-native-select影子树里的原生 <select>
pt-select影子树里 role="combobox" 的触发器
pt-checkbox / pt-switch / pt-radio影子树里的方框 / 轨道 / 圆点(外部标签优先于插槽文字)
pt-radio-group宿主上的 role="radiogroup"(经 ElementInternals)
pt-slider单滑块:影子树里的 role="slider";多滑块:宿主的 role="group"(经 ElementInternals)
pt-combobox影子树里 role="combobox" 的输入框
html
<pt-label for="email" required>邮箱地址</pt-label>
<pt-input id="email" type="email" required></pt-input>
  • 标签晚于控件出现、控件晚于标签出现、控件换了 id、标签被移除、标签文字改了 —— 关联都跟着更新。
  • 标签优先:控件上同时写了 aria-label 时,以标签文字为准(与原生 aria-labelledby 优先于 aria-label 一致); 标签移除后退回控件自己的 aria-label。pt-radio-group 例外:它的名字在宿主上,宿主写的 aria-label 优先。
  • 多个标签指向同一个控件时,按页面顺序拼成一个名字。
  • 指向原生 <input> 等非 kit 元素时只有点击转交,没有可访问名关联 —— 原生元素请用原生 <label>。

各浏览器的差异 ​

关联同时走两条路,读屏念出的名字在各浏览器里一致,差别只在机制:

浏览器机制
Chrome / Edge 135+、Firefox 136+、Safari 16.4+ARIA 元素反射:内部元素的 aria-labelledby 直接引用外部的 pt-label 元素,读屏能跳到标签
Chrome 114–134、Firefox 125–135标签文字镜像进内部元素的 aria-label,文字变化时同步;读屏念得出名字,但不知道「由哪个元素标注」

镜像在支持反射的浏览器里也会写,只是不生效(aria-labelledby 优先):axe、Playwright 的 getByLabel 这类工具 只认 id 形式的 aria-labelledby,看不到反射出来的引用,靠镜像才能验证。 镜像是简化的文字提取:跳过 aria-hidden 与 hidden 的内容,子元素有 aria-label 时用它。

required 的星号对读屏隐藏(aria-hidden),它只是视觉提示;必填语义写在控件的 required 上, 控件会带上 aria-required 并参与表单校验。disabled 同理,只改标签的外观与点击行为,控件要自己禁用。

勾选类控件的文字本来就能放进它们自己的插槽(<pt-checkbox>同意条款</pt-checkbox>), 点文字切换、可访问名都是现成的 —— 优先这么写,只有布局上文字必须和控件分开时才用 pt-label。

API ​

属性

属性Attribute类型默认值说明
disableddisabledbooleanfalse禁用:半透明、禁用光标,点击不再转交焦点。一般与目标控件的 disabled 同步设置
htmlForforstring | undefined—关联控件的 id,attribute 是 `for`(与原生 label 相同)。property 叫 `htmlFor`: `for` 是 JS 保留字,框架包装层生成的解构与类型声明里当不了标识符; 这也是 React 与 DOM(HTMLLabelElement.htmlFor)的既有叫法。
requiredrequiredbooleanfalse必填:文字后面跟一个危险色的星号。只是视觉提示,必填语义请写在目标控件上

插槽

名称说明
(默认)标签文字

可定制的内部元素(::part())

part说明
base文字容器
required必填星号

Apache-2.0 协议开源