@fiscozen/textarea

中文文档
3.4.1发布于 2026/10/23MITES Module近 30 天下载 2578

Design System Textarea component

原始使用文档
文档目录13 节
  1. Development
  2. Setup
  3. Architecture
  4. Code Organization
  5. Dependencies
  6. Key Concepts
  7. Testing
  8. Adding Features
  9. Build
  10. Breaking Changes
  11. Removed errorMessage and helpMessage props (replaced with s…
  12. Deprecated size prop
  13. Removed FzTextareaEvents type and explicit event emits

@fiscozen/textarea

Multi-line text input component with label, validation states, resize control, and WCAG 2.1 AA accessibility.

For usage documentation, see Storybook Documentation

Development

Setup

pnpm install
pnpm --filter @fiscozen/textarea build

Architecture

FzTextarea is a form component that wraps a native <textarea> element with label, validation states (error/valid), help/error messages, and full ARIA accessibility. Error messages use FzAlert for consistency with FzInput.

Key design decisions:

  • Auto-generated IDs: When no id prop is provided, a unique ID is generated via utils.ts to ensure label-textarea association always works. Uses timestamp + counter pattern (same as @fiscozen/input).
  • ARIA ternary pattern: Boolean ARIA attributes use ternary expressions (e.g. :aria-invalid="error ? 'true' : 'false'") because Vue 3 removes boolean attributes when false, but ARIA spec requires string values.
  • Error via FzAlert: Error messages use <FzAlert tone="error" variant="text"> with role="alert", matching FzInput pattern. The circle-xmark icon is rendered automatically by FzAlert. Dependency: @fiscozen/alert.
  • Slot-based messages: Error and help content are provided via errorMessage and helpText slots, matching FzInput pattern. Uses defineSlots for TypeScript typing and useSlots() for runtime slot detection (same approach as FzInput).
  • Custom focus ring: Browser default outline is suppressed (outline-none focus:ring-0 focus:outline-none) and replaced with a border color change on focus (focus:border-blue-600). In error state, focus uses focus:border-semantic-error-300 to maintain error context. This approach differs from FzInput which uses has-[:focus] on a wrapper div; here the border is directly on the <textarea> element.
  • Design token alignment (Figma): Border colors use semantic-error-200 (default error) / semantic-error-300 (error+focus). Placeholder uses placeholder:text-grey-300. Background bg-core-white, text text-core-black. Text is always text-base (16px) matching Figma spec (no size variants). Label and help text use font-normal text-base. Disabled/readonly states apply text-grey-300 to label and help text.
  • Deprecated size prop: The size prop (sm | md | lg) is accepted for backward compatibility but ignored. The textarea always renders with text-base. A runtime console.warn is emitted when any value is passed. Will be removed in the next major version.
  • inheritAttrs: false + v-bind="$attrs": Extra attributes and native event listeners are forwarded directly to the native <textarea> element, not the root wrapper div. No custom defineEmits for DOM events — blur, focus, paste, keydown, etc. all flow through $attrs automatically.
  • defineExpose({ textareaRef }): Exposes the native <textarea> element ref for programmatic focus or measurement, following the same pattern as FzInput (inputRef, containerRef).
  • Label ID + aria-labelledby: Label element gets an explicit id ({effectiveId}-label) and the textarea uses aria-labelledby to reference it, providing stronger screen reader association alongside for/id binding. Same pattern as FzInput.
  • watch for deprecation: Uses watch(() => props.size, ..., { immediate: true }) instead of onMounted for deprecation warnings, aligning with FzInput's watcher-based approach. Catches runtime prop changes.
  • Root identification class: fz-textarea class on root div for debugging and external styling, mirroring FzInput's fz-input class.
  • Combined states: Error+disabled, required+help, disabled+compiled are all supported. When error+disabled, both aria-invalid and aria-disabled are set to "true", and the error message remains visible. Help text is greyed out when disabled/readonly.
  • Minimum width/height: min-w-[96px] prevents horizontal collapse; min-h-[77px] enforces minimum height with rows: 2 default (2 rows content + 10px padding top + 10px padding bottom + 1px border top + 1px border bottom).
  • Auto-height: When autoHeight is true, the textarea height is adjusted programmatically on every v-model change via adjustHeight(). A ResizeObserver is used for external size changes. Vertical resize is disabled; horizontal is preserved. Font metrics (lineHeight, paddingY, borderY) are cached once at mount because they are fixed by the design system. maxRows caps the growth; beyond that a scrollbar appears (overflow-y: auto). autoHeight must be set at mount — runtime changes are not supported because hooks (onMounted, watch) are registered conditionally at setup time.

Code Organization

  • src/FzTextarea.vue: Main component (imports FzAlert, FzIcon)
  • src/types.ts: Type definitions (FzTextareaProps)
  • src/utils.ts: ID generation utility (generateTextareaId)
  • src/index.ts: Public exports

Dependencies

  • @fiscozen/alert (workspace): FzAlert for error messages
  • @fiscozen/icons (peer): FzIcon for valid check icon

Key Concepts

Effective ID

The component computes an effectiveId that falls back to an auto-generated ID when no explicit id prop is provided. This ensures:

  • Label for attribute always matches textarea id
  • Label id ({effectiveId}-label) is referenced by aria-labelledby on the textarea
  • aria-describedby references (error/help IDs) are always valid
  • Error message container ID ({effectiveId}-error) and help message ID ({effectiveId}-help) are deterministic

Auto Height Algorithm

When autoHeight is enabled:

  1. Mount: measureMetrics() reads lineHeight, paddingTop+paddingBottom, borderTopWidth+borderBottomWidth from getComputedStyle(). These are cached for the component lifetime.
  2. On input (watch(model)): adjustHeight() is called after nextTick. It resets height to "auto" so scrollHeight reflects the natural content height, then computes the constrained height: if maxRows is set and scrollHeight > maxRows * lineHeight + paddingY, it caps the height and sets overflow-y: auto; otherwise overflow-y: hidden.
  3. ResizeObserver: Watches for external width changes (e.g. container resize) that could reflow text, calling adjustHeight() to recalculate.
  4. Cleanup: Observer is disconnected in onBeforeUnmount.

The autoHeightResizeMap object maps resize prop values to their auto-height equivalent, stripping vertical resize while preserving horizontal.

Slot Priority

When both errorMessage and helpText slots are provided, error takes precedence (only shown when error prop is true). The ariaDescribedBy computed uses useSlots() (runtime) to detect which slots are provided, following the same priority: error ID > help ID. This matches FzInput's approach where defineSlots is only for TypeScript typing.

Testing

Running Tests

pnpm --filter @fiscozen/textarea test:unit
pnpm --filter @fiscozen/textarea coverage

Test Structure

Tests are organized in nested describe blocks:

  • Rendering: Basic component rendering, FzAlert integration
  • Props: Each prop has its own describe block
  • Events: Native event forwarding via $attrs, v-model
  • Expose: textareaRef availability and type
  • Accessibility: ARIA attributes (including aria-labelledby), role="alert", decorative icons, keyboard navigation
  • CSS Classes: Static and dynamic class application
  • Edge Cases: Null/undefined/empty values, special characters, combined states (error+disabled, help+disabled, required+help)
  • Auto Height: Resize class mapping, warnings (maxRows without autoHeight, vertical resize), height adjustment, overflow-y behavior
  • Snapshots: All major states and combinations with explicit IDs for stability

Snapshot Stability

Snapshot tests provide explicit id props to avoid auto-generated IDs (which contain timestamps) from causing flaky comparisons across test runs.

Adding Features

  1. Update types in src/types.ts with JSDoc
  2. Implement logic in src/FzTextarea.vue
  3. Add tests in src/__tests__/FzTextarea.spec.ts
  4. Update Storybook stories in apps/storybook/src/stories/form/Textarea.stories.ts
  5. Update MDX documentation in apps/storybook/src/FzTextarea.mdx

Build

pnpm --filter @fiscozen/textarea build

Breaking Changes

Removed errorMessage and helpMessage props (replaced with slots)

The errorMessage and helpMessage props have been removed. Error and help content are now provided via named slots, aligning with FzInput and FzSelect patterns.

Before:

<FzTextarea label="Notes" :error="hasError" errorMessage="Error text" helpMessage="Help text" />

After:

<FzTextarea label="Notes" :error="hasError">
  <template #errorMessage>Error text</template>
  <template #helpText>Help text</template>
</FzTextarea>

Deprecated size prop

The size prop is accepted but ignored. The textarea always uses text-base (16px). A runtime warning is emitted when any value is passed. Will be removed in the next major version.

Removed FzTextareaEvents type and explicit event emits

Native DOM events (blur, focus, paste, etc.) are no longer declared via defineEmits. They are forwarded automatically to the native <textarea> via v-bind="$attrs" (with inheritAttrs: false). The FzTextareaEvents type has been removed from exports.

Before:

<FzTextarea label="Notes" @blur="onBlur" />
<!-- Worked via defineEmits + explicit emit('blur', $event) -->

After:

<FzTextarea label="Notes" @blur="onBlur" @keydown="onKeydown" />
<!-- Works via $attrs forwarding. Any native event is supported. -->

版本与发布记录

@fiscozen/textarea 共发布 19 个版本,首次发布于 2024/07/25;过去 12 个月发布了 16 个版本。

版本发布日期距今
3.4.1latest2026/10/2323 天前
3.4.02026/10/2026 天前
3.3.12026/09/291 个月前
3.3.02026/09/072 个月前
3.2.02026/08/282 个月前
3.1.42026/07/173 个月前

关于 @fiscozen/textarea 的常见问题

@fiscozen/textarea 是什么?

Design System Textarea component

如何安装 @fiscozen/textarea?

在项目目录运行 npm install @fiscozen/textarea,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:vue(^3.4.13)、tailwindcss(^3.4.1)、@fiscozen/icons(^1.0.8)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@fiscozen/textarea 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/fiscozen__textarea 是否存在。

@fiscozen/textarea 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@fiscozen/textarea 可以商用吗?

@fiscozen/textarea 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@fiscozen/textarea 的下载量有多少?

根据 npm 官方下载统计,@fiscozen/textarea 在 2026/10/15 – 2026/11/13 这 30 天内被下载 2,578 次,日均约 86 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fiscozen/textarea 还在维护吗?

最新版本 3.4.1 发布于 2026/10/23(23 天前);至今共发布 19 个版本,其中过去 12 个月发布了 16 个;首次发布于 2024/07/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。