cds-textarea 渲染结构全解析:从快照到源码的 Carbon Web Components 多行文本框深度指南
【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon
cds-textarea是 IBM Carbon Design System 在 Web Components 包(@carbon/web-components)中提供的多行文本输入组件。本指南以 cds-textarea 渲染快照文档 为骨架,逐层拆解其完整的 Shadow DOM 渲染结构,并结合 textarea.ts 源码、单元测试 与 Storybook 示例,讲清它的全部属性、插槽、计数器、校验状态与骨架屏变体,帮助你在真实项目中正确使用与排查该组件。
快照文档是什么:组件渲染的“契约基准”
在packages/web-components/tests/snapshots/目录下存放着一批以组件命名的 Markdown 快照(cds-btn.md、cds-input.md、cds-textarea.md、data-table.md等)。它们记录的是组件在指定测试场景下渲染出的完整 DOM 输出,本质上是组件渲染行为的“契约基准”——任何一次模板结构调整都会导致快照内容变化,从而被版本控制系统捕获。cds-textarea.md对应的是Should render with various attributes场景,即组件同时携带disabled、placeholder、readonly、rows等多种属性时的最终渲染结果,是观察该组件输出结构最直接的入口。
从快照看完整渲染结构:四层 DOM 解剖
快照中cds-textarea的 Shadow DOM 输出由四个结构块组成,下面逐层说明每个节点在 textarea.ts 的render()方法中对应的实现位置与作用。
第一层:标签与计数器区域(cds--text-area__label-wrapper)
<div class="cds--text-area__label-wrapper"> <label class="cds--label cds--label--disabled" for="input"> <slot name="label-text"></slot> </label> </div>- 标签通过
<slot name="label-text">渲染,默认内容(label属性文本)作为 slot 的回退值。 - 快照中标签带
cds--label--disabled,因为场景中设置了disabled属性,对应源码中labelClasses的classMap逻辑(textarea.ts)。 for="input"与内部<textarea id="input">建立关联,保证点击标签可聚焦输入区。- 当启用计数器时,同一个
label-wrapper内还会渲染计数标签cds--text-area__label-counter(默认不出现,见后文“计数器”一节)。
第二层:文本域包装(cds--text-area__wrapper)
<div class="cds--text-area__wrapper cds--text-area__wrapper--readonly"> <textarea class="cds--text-area" disabled="" id="input" placeholder="placeholder-foo" readonly="" rows="4"> </textarea> </div>- 内部
<textarea>的类名为cds--text-area,并携带id="input"、placeholder="placeholder-foo"、rows="4"、disabled=""、readonly="",与快照场景设置一一对应。 - 包装节点带
cds--text-area__wrapper--readonly修饰类(textarea.ts),设置cols时还会追加cds--text-area__wrapper--cols。 - 源码中
<textarea>会接收autocomplete、autofocus、cols、name、pattern、maxlength、value等透传属性,并绑定keydown、paste、input、change四个事件(textarea.ts)。 - 校验状态下,同一层还会出现
data-invalid属性、WarningFilled16(invalid)或WarningAltFilled16(warn)图标,以及ai-label、slug插槽。
第三层:辅助文本(cds--form__helper-text)
<div class="cds--form__helper-text cds--form__helper-text--disabled"> <slot name="helper-text"> helper-text-foo </slot> </div>- 辅助文本通过
<slot name="helper-text">渲染,helperText属性作为默认回退内容(此处显示helper-text-foo)。 disabled时带cds--form__helper-text--disabled,对应源码 textarea.ts 的helperTextClasses。
第四层:校验消息容器(cds--form-requirement)
<div class="cds--form-requirement" hidden=""> <slot name="warn-text"></slot> </div>- 该容器在无校验状态时带
hidden属性,仅在invalid或warn为真时显示。 - 插槽名动态切换:
invalid时为invalid-text,否则为warn-text,默认回退内容分别为invalidText/warnText属性(textarea.ts)。 - fluid 变体(
isFluid)的布局差异:fluid 模式下校验消息与分割线<hr class="cds--text-area__divider" />被渲染在textarea__wrapper内部;非 fluid 模式下辅助文本与校验消息渲染在包装之外(textarea.ts)。
属性 API:继承自 CDSTextInput 的完整清单
CDSTextarea直接继承CDSTextInput(textarea.ts),因此先继承 text-input 的全部表单属性,再叠加自身专属属性。以下属性均可通过 HTML 属性或 JS property 使用:
| 属性 | 类型/默认值 | 说明 | 定义位置 |
|---|---|---|---|
cols | Number / 未定义 | 文本域默认列数,设置后 wrapper 追加--cols类 | textarea.ts |
rows | Number /4 | 文本域默认行数 | textarea.ts |
counter-mode | 'character' \| 'word',默认'character' | 计数器计算方式,非法值变更会被hasChanged拦截 | textarea.ts |
is-fluid | Boolean /false | 是否使用 fluid 样式 | textarea.ts |
enable-counter | Boolean /false | 是否显示计数器 | text-input.ts |
max-count | Number / 未定义 | 计数上限;character 模式下同步为maxlength | text-input.ts |
label/hide-label | String / Boolean | 标签文本 / 是否视觉隐藏标签(cds--visually-hidden) | text-input.ts |
helper-text | String | 辅助说明文本 | text-input.ts |
invalid/invalid-text | Boolean / String | 无效状态及提示文案 | text-input.ts |
warn/warn-text | Boolean / String | 警告状态及提示文案 | text-input.ts |
disabled/readonly/required | Boolean | 禁用 / 只读 / 必填 | text-input.ts |
pattern | String | HTML 校验正则,如[A-Za-z]+ | textarea.ts |
placeholder/autocomplete/autofocus/name | String / Boolean | 原生输入属性透传 | text-input.ts |
value | String | 当前值,getter/setter 直接读写内部<textarea> | text-input.ts |
value的双向同步机制值得注意:setter在设置内部_value的同时会直接写入_input.value,保证程序化赋值能即时反映到 UI;_handleInput又将用户输入同步回组件value(textarea.ts)。
计数器机制:character 与 word 两种模式
enable-counter与max-count同时满足时,标签行右侧渲染当前值/上限的计数标签:
- character(默认)模式:按
value.length计数,同时把max-count写入原生maxlength,由浏览器强制限制输入长度。 - word 模式:按正则
\p{L}+/gu匹配的 Unicode 字母序列计数,并且不设置maxlength(因为 word 模式无法用原生属性表达),改为在事件层手动拦截:_onKeyDown在词数已达上限时阻止空格与回车键输入(textarea.ts);_onPaste在粘贴导致超限时阻止默认粘贴,截取前maxCount个词后重新触发input事件(textarea.ts)。
模式切换时updated()会动态添加/移除maxlength(textarea.ts),测试用例 textarea-test.js 完整覆盖了 character→word→character 的往返切换行为。
校验与提示状态:invalid / warn / helper 的优先级
渲染逻辑严格遵循以下优先级(与cds-select等组件对齐):
invalid优先:显示WarningFilled16图标与invalid-text;- 否则
warn:显示WarningAltFilled16警告图标与warn-text; - 辅助文本仅在无 invalid/warn 时可见。
在非 fluid 布局中,校验消息或辅助文本二选一渲染(validationMessage || helper的等价逻辑),这与快照中cds--form-requirement默认hidden的行为一致。对应测试见 textarea-test.js。
插槽:label-text / helper-text / invalid-text / warn-text / ai-label / slug
组件提供 6 个命名插槽,均可覆盖对应属性文本(textarea.ts 的 JSDoc 声明):
| 插槽名 | 作用 |
|---|---|
label-text | 覆盖标签文本 |
helper-text | 覆盖辅助文本 |
invalid-text | 覆盖无效提示(需invalid) |
warn-text | 覆盖警告提示(需warn) |
ai-label | 注入 AI Label 装饰(触发_handleSlotChange检测) |
slug | 旧版 slug 装饰位(v12 移除) |
插槽渲染的测试用例集中在 textarea-test.js,使用assignedNodes({ flatten: true })断言插槽内容生效。
骨架屏与 AI Label 扩展
- 骨架屏变体:
cds-textarea-skeleton是独立的轻量元素,渲染一条cds--label cds--skeleton(可被hide-label关闭)和一个cds--skeleton cds--text-area占位块(textarea-skeleton.ts)。测试验证了默认与hide-label两种渲染(textarea-test.js)。 - AI Label 支持:在
ai-label插槽中放入<cds-ai-label>后,wrapper 会追加cds--text-area__wrapper--decorator类,AI 标签以size="mini"内嵌显示,示例见 textarea.stories.ts 的WithAILabelstory。
事件与表单集成
input:用户输入时触发并同步value;change:原生change事件不冒泡穿透 Shadow DOM,组件通过_handleChange重新派发一个composed: true的change事件,保证宿主上监听生效(text-input.ts);FormData集成:_handleFormdata在非disabled时把name/value追加进表单数据(text-input.ts);- 组件设置
delegatesFocus: true,点击标签或容器空白处焦点直达内部<textarea>。
此外,updated()中通过ResizeObserver监听 wrapper 尺寸变化,将辅助文本与校验消息的max-width对齐 wrapper 宽度并启用overflow-wrap: break-word,避免设置cols后提示文字溢出(textarea.ts)。
测试验证与无障碍
textarea-test.js 共覆盖 20+ 场景,包括:标签/辅助文本渲染、value反射、readonly/disabled、invalid/warn文案、hide-label、cols/rows反射、pattern/required、data-*透传、计数器模式切换、全部插槽渲染,以及await expect(el).to.be.accessible()的无障碍断言(textarea-test.js)。快照文档 cds-textarea.md 中的 DOM 输出正是这些渲染路径的稳定基准。
快速上手示例
通过 npm 安装@carbon/web-components后引入组件(使用方式与 Storybook 中的 Default story 一致):
<cds-form-item> <cds-textarea label="TextArea label" helper-text="TextArea helper text" rows="4" enable-counter counter-mode="character" max-count="500" placeholder="Enter your feedback"></cds-textarea> </cds-form-item>import '@carbon/web-components/es/components/textarea/index.js';自定义插槽、校验与 AI 装饰的完整用法可进一步查阅 textarea.mdx 组件文档与 textarea.stories.ts 中的Default、Skeleton、WithAILabel、WithLayer四个 story。
【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考