cds-textarea 渲染结构全解析:从快照到源码的 Carbon Web Components 多行文本框深度指南
2026/9/16 17:15:27 网站建设 项目流程

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.mdcds-input.mdcds-textarea.mddata-table.md等)。它们记录的是组件在指定测试场景下渲染出的完整 DOM 输出,本质上是组件渲染行为的“契约基准”——任何一次模板结构调整都会导致快照内容变化,从而被版本控制系统捕获。cds-textarea.md对应的是Should render with various attributes场景,即组件同时携带disabledplaceholderreadonlyrows等多种属性时的最终渲染结果,是观察该组件输出结构最直接的入口。

从快照看完整渲染结构:四层 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属性,对应源码中labelClassesclassMap逻辑(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>会接收autocompleteautofocuscolsnamepatternmaxlengthvalue等透传属性,并绑定keydownpasteinputchange四个事件(textarea.ts)。
  • 校验状态下,同一层还会出现data-invalid属性、WarningFilled16(invalid)或WarningAltFilled16(warn)图标,以及ai-labelslug插槽。

第三层:辅助文本(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属性,仅在invalidwarn为真时显示。
  • 插槽名动态切换: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 使用:

属性类型/默认值说明定义位置
colsNumber / 未定义文本域默认列数,设置后 wrapper 追加--colstextarea.ts
rowsNumber /4文本域默认行数textarea.ts
counter-mode'character' \| 'word',默认'character'计数器计算方式,非法值变更会被hasChanged拦截textarea.ts
is-fluidBoolean /false是否使用 fluid 样式textarea.ts
enable-counterBoolean /false是否显示计数器text-input.ts
max-countNumber / 未定义计数上限;character 模式下同步为maxlengthtext-input.ts
label/hide-labelString / Boolean标签文本 / 是否视觉隐藏标签(cds--visually-hiddentext-input.ts
helper-textString辅助说明文本text-input.ts
invalid/invalid-textBoolean / String无效状态及提示文案text-input.ts
warn/warn-textBoolean / String警告状态及提示文案text-input.ts
disabled/readonly/requiredBoolean禁用 / 只读 / 必填text-input.ts
patternStringHTML 校验正则,如[A-Za-z]+textarea.ts
placeholder/autocomplete/autofocus/nameString / Boolean原生输入属性透传text-input.ts
valueString当前值,getter/setter 直接读写内部<textarea>text-input.ts

value的双向同步机制值得注意:setter在设置内部_value的同时会直接写入_input.value,保证程序化赋值能即时反映到 UI;_handleInput又将用户输入同步回组件value(textarea.ts)。

计数器机制:character 与 word 两种模式

enable-countermax-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等组件对齐):

  1. invalid优先:显示WarningFilled16图标与invalid-text
  2. 否则warn:显示WarningAltFilled16警告图标与warn-text
  3. 辅助文本仅在无 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: truechange事件,保证宿主上监听生效(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/disabledinvalid/warn文案、hide-labelcols/rows反射、pattern/requireddata-*透传、计数器模式切换、全部插槽渲染,以及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 中的DefaultSkeletonWithAILabelWithLayer四个 story。

【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon

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

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

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

立即咨询