@phila/phila-ui-text-area
v1.0.0-beta.3
Published
A textarea input component for Phila UI.
Readme
TextArea Component
A multi-line text input with an optional label, supporting text, error messaging, and a
character-limit counter. Supports both v-model (controlled) and uncontrolled use.
Features
- 🎨 Customizable label, placeholder, and supporting text
- 🔢 Built-in character-limit counter, on by default (500, matching the Phila 311 design) — override the limit or turn it off entirely
- 📏 Dynamic error handling with customizable messages
- ♿ Accessibility features: focus states, disabled state
Installation
pnpm add @phila/phila-ui-text-area @phila/phila-ui-core
# or
npm install @phila/phila-ui-text-area @phila/phila-ui-coreImport core styles in your main entry file (e.g., main.js|ts):
import "@phila/phila-ui-core/styles/template-light.css";Usage
<script setup lang="ts">
import { ref } from "vue";
import { TextArea } from "@phila/phila-ui-text-area";
const comment = ref("");
</script>
<template>
<TextArea v-model="comment" label="Add a comment (optional)" placeholder="Enter comment here..." />
</template>Character limit
maxLength defaults to 500 — the field enforces it (native maxlength) and shows a live
x/500 characters counter without any extra props. Pass a different number for a different limit,
or null to turn the counter off entirely:
<TextArea v-model="comment" :max-length="140" />
<TextArea v-model="comment" :max-length="null" />Props
| Prop | Type | Default | Description |
| ---------------- | -------------------- | -------------- | ---------------------------------------------------------------------------------------------------------- |
| modelValue | string | undefined | Bound value (v-model). Works uncontrolled too — omit it and the field manages its own value internally. |
| label | string | "" | Label text for the field |
| placeholder | string | "" | Placeholder text when the field is empty |
| supportingText | string | "" | Helper text shown below the label, above the field |
| error | string \| string[] | [] | Error message(s). Only the first is displayed, even if an array with several entries is passed. |
| maxLength | number \| null | 500 | Character limit — shows a live counter and sets the native maxlength. null hides the counter. |
| rows | number | 4 | Number of visible text rows |
| id | string | auto-generated | ID for the textarea element |
| className | string | "" | Additional CSS classes |
| disabled | boolean | false | Not a declared prop — passed through as a native HTML attribute and detected via useAttrs() for styling. |
| required | boolean | false | Same as disabled — a native attribute, not a declared prop. |
Slots
| Slot | Description |
| -------------- | --------------------------------------------------------------- |
| before-input | Extra content between the supporting text and the field itself. |
Events
| Event | Payload | Description |
| ------------------- | -------- | -------------------------------- |
| update:modelValue | string | Emitted on input, for v-model. |
Exposed
Access via a template ref on TextArea:
| Property | Type | Description |
| ------------- | ---------------------------------- | ------------------------------------------- |
| textareaRef | Ref<HTMLTextAreaElement \| null> | The underlying native <textarea> element. |
Development
Install Dependencies
pnpm installRun Demo
pnpm devRun lint
pnpm lintCreate Production Build
pnpm buildTest locally in your development environment
npm pack
cp ./dist/*.tgz ~/path/to/your/local/npm/repo
cd ~/path/to/your/local/npm/repo
npm install *.tgzPublishing to NPM
Follow the release instructions using changesets.
License
MIT
