Components · Data Entry
Textarea
Enter multi-line free text — descriptions, messages, notes — with autosize and char count, rendered through the shared Textarea.
Examples
<!-- Paste-and-run: save as .html and open in a browser. No build step, no bundler.
Textarea is a COMPOSITE (antd, no framework-free element), so its HTML form is a CDN-React
page — React + antd load from a CDN (esm.sh) and mount on open. It consumes the SAME shared
`textareaTheme` the React/Vue wrappers use, so it renders the DS V3 look (radius 8, #E3E3E3
border, brand focus/hover, #8A8A8A placeholder).
No JSX here (JSX needs a compiler) — we use React.createElement via the `h` alias. -->
<div id="root"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import { createRoot } from 'https://esm.sh/react-dom@18/client';
import { ConfigProvider, Input } from 'https://esm.sh/antd@6?deps=react@18,react-dom@18';
import { textareaTheme } from 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/textarea-theme.js';
const h = React.createElement;
const { TextArea } = Input;
// size: 'small' | 'middle' (default) | 'large' → control height 24 / 32 / 40
// status: 'error' | 'warning' → recolours the border for validation
createRoot(document.getElementById('root')).render(
h(ConfigProvider, { theme: textareaTheme },
h('div', { style: { display: 'grid', gap: 12, width: 340 } },
h(TextArea, { placeholder: 'Describe your event', size: 'middle',
autoSize: { minRows: 3, maxRows: 6 }, showCount: true, maxLength: 200 }),
h(TextArea, { status: 'error', defaultValue: 'Fix this', autoSize: { minRows: 2 } }),
h(TextArea, { readOnly: true, defaultValue: 'Read-only content' }),
h(TextArea, { disabled: true, placeholder: 'Disabled' })
)
)
);
</script>
import { ConfigProvider, Input } from 'antd'; // antd v6
import { textareaTheme } from '@ahaslides-product/design/textarea-theme';
const { TextArea } = Input;
<ConfigProvider theme={textareaTheme}>
{/* size: 'small' | 'middle' (default) | 'large' → control height 24 / 32 / 40 */}
{/* status: 'error' | 'warning' → recolours the border for validation */}
<TextArea
placeholder="Describe your event"
size="middle"
status={hasError ? 'error' : undefined}
autoSize={{ minRows: 3, maxRows: 6 }}
showCount
maxLength={200}
onChange={(e) => setText(e.target.value)}
style={{ width: 340 }}
/>
{/* Non-editable states inherit the same theme */}
<TextArea readOnly value="Read-only content" style={{ width: 340 }} />
<TextArea disabled placeholder="Disabled" style={{ width: 340 }} />
</ConfigProvider>
// One shared textareaTheme → the DS V3 look; size/status/disabled/readOnly all inherit it.
// autoSize grows with content, showCount surfaces the cap.
<script setup>
import { ref } from 'vue';
import { ConfigProvider, Input } from 'ant-design-vue'; // ant-design-vue v4
import { textareaTheme } from '@ahaslides-product/design/textarea-theme';
const Textarea = Input.TextArea;
const text = ref('');
const hasError = ref(false);
</script>
<template>
<a-config-provider :theme="textareaTheme">
<!-- size: 'small' | 'middle' (default) | 'large' → control height 24 / 32 / 40 -->
<!-- status: 'error' | 'warning' → recolours the border for validation -->
<Textarea
v-model:value="text"
placeholder="Describe your event"
size="middle"
:status="hasError ? 'error' : undefined"
:auto-size="{ minRows: 3, maxRows: 6 }"
show-count
:maxlength="200"
style="width: 340px"
/>
<!-- Non-editable states inherit the same theme -->
<Textarea read-only value="Read-only content" style="width: 340px" />
<Textarea disabled placeholder="Disabled" style="width: 340px" />
</a-config-provider>
</template>
<!-- The SAME textareaTheme as React → one DS V3 look across both vendor libraries. -->
// @ahaslides-product/design/textarea-theme — declared ONCE, consumed by both tiers.
import { textareaTheme } from '@ahaslides-product/design/textarea-theme';
export const textareaTheme = {
token: {
colorPrimary: '#6A1EBB',
borderRadius: 8,
colorBorder: '#E3E3E3',
colorTextPlaceholder: '#8A8A8A',
fontFamily: 'var(--aha-font-product, "Plus Jakarta Sans", sans-serif)',
},
components: {
Input: {
activeBorderColor: '#6A1EBB', // brand focus border
hoverBorderColor: '#D3B4FF', // purple-30 hover border
borderRadius: 8,
},
},
};
API
| Prop | Type | Default | Notes |
|---|---|---|---|
value | string | "" | Controlled text value |
size | 'small' | 'middle' | 'large' | 'middle' | Control height / padding: small 24, default 32, large 40 |
status | 'error' | 'warning' | — | Validation state — recolours the border |
disabled | boolean | false | Non-interactive; greyed fill |
readOnly | boolean | false | Shows value but blocks editing |
placeholder | string | — | Empty-state hint (#8A8A8A) |
rows | number | — | Fixed visible rows |
autoSize | boolean | { minRows, maxRows } | false | Grow with content between bounds |
maxLength | number | — | Cap length; pair with showCount |
showCount | boolean | false | Show the character counter |
onChange | (e) => void | — | Fires on each change; read e.target.value |
Install
# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} # a GitHub token with read:packages
npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css'; // once, at the app root
import '@ahaslides-product/design/textarea-theme'; // registers <textarea>
Agent feed for this component (absolute, fetchable anywhere): textarea.agent.json · textarea.md · textarea.llms.txt
When to use
When to use
- Textarea — multi-line free text — a description, a message, notes
- Input — short single-line text — a name, a title, a search term
- Select — one value from a known set — don't make the user type it
Prefer autoSize with a minRows/maxRows band so the field grows with content but never dominates the layout. Pair maxLength with showCount so the limit is visible, not a surprise on submit.
Surfaces
editor dashboard settings audience
Spec
Box radius 8 · 1px #E3E3E3 border · padding 4 11 · Hover #D3B4FF (purple-30) border · Focus brand #6A1EBB border · Text Plus Jakarta 14/21; placeholder #8A8A8A · Sizing rows or autoSize={{minRows,maxRows}} · Size small · default · large (control height 24/32/40) · Status error #F5222D · warning #FAAD14 border