TextArea
Overviewimport { TextArea, TextAreaResize } from '@nili/ui';This is the library’s own overview page, rendered live. Switch the language or the theme in the header and it follows.
Label, hint and error
The presence of error is what marks the field invalid, so the border and the message can never disagree — there is no separate invalid flag to forget.
Markdown is supported.
Please write at least twenty characters.
import { TextArea } from "@nili/ui"
export function Example() {
return (
<>
<TextArea
label="Description"
placeholder="Tell us a little about the project…"
hint="Markdown is supported."
rows={4}
/>
<TextArea
label="Description"
defaultValue="Too short"
error="Please write at least twenty characters."
rows={4}
/>
</>
)
}Character counter
showCount puts used / limit under the field. countLimit sets a soft limit without also setting maxLength — a hard maxLength silently swallows the end of a paste, which is worse than showing someone they are over.
import { TextArea } from "@nili/ui"
export function Example() {
const [value, setValue] = useState("")
return (
<>
{/* soft limit: typing past it is allowed, and shown */}
<TextArea
label="Bio"
showCount
countLimit={120}
value={value}
onChange={(e) => setValue(e.target.value)}
rows={3}
/>
{/* hard limit */}
<TextArea label="Tweet" showCount maxLength={280} rows={3} />
{/* custom format */}
<TextArea
label="Notes"
showCount
countLimit={200}
formatCount={(used, limit) => `${used} of ${limit}`}
rows={3}
/>
</>
)
}Resize handles
Which handles the browser offers. vertical is the default; none for a field inside a tight layout that must not be dragged out of shape.
import { TextArea } from "@nili/ui"
export function Example() {
return (
<>
<TextArea label="Vertical (default)" resize="vertical" rows={3} />
<TextArea label="Both axes" resize="both" rows={3} />
<TextArea label="Fixed" resize="none" rows={3} />
</>
)
}Auto resize
Grows with the content instead of scrolling, up to maxRows. Off by default: a field that resizes on every keystroke moves everything below it, which is unpleasant in a long form.
import { TextArea } from "@nili/ui"
export function Example() {
return (
<TextArea
label="Message"
autoResize
maxRows={8}
rows={2}
placeholder="Type a few lines…"
/>
)
}TextArea
extends Omit< ComponentPropsWithoutRef<'textarea'>, 'size' >
Other props
| Prop | Type | Default | Notes |
|---|---|---|---|
| children | ReactNode | — | |
| disabled | boolean | — | |
| required | boolean | — | |
| readOnly | boolean | — | |
| checked | boolean | — | |
| defaultChecked | boolean | — | |
| placeholder | string | — | |
| value | string | — | |
| defaultValue | string | — | |
| name | string | — | |
| maxLength | number | — | |
| rows | number | 4 | |
| autoComplete | string | — | |
| aria-label | string | — | |
| label | ReactNode | — | |
| hint | ReactNode | — | |
| error | ReactNode | — | Validation message. Its presence is what marks the field invalid, so the border and the message can never disagree. |
| resize | none | vertical | both | vertical | Which handles the browser offers. |
| autoResize | boolean | false | Grow with the content instead of scrolling, up to `maxRows`. Off by default: a field that resizes on every keystroke moves everything below it, which is unpleasant in a long form. |
| maxRows | number | 10 | |
| showCount | boolean | false | Shows `used / limit` under the field. Pass a number to set the limit without also passing `maxLength` — see the note in the component about why those are different things. |
| countLimit | number | — | Soft limit for the counter. Defaults to `maxLength` when that is set. |
| formatCount | (used: string, limit: string) => string | — | Formats the counter, e.g. `` (used, limit) => `${used} of ${limit}` ``. |
| locale | string | — | BCP-47 tag driving the counter digits (`'fa'` → Persian). Defaults to the ambient locale from `NiliProvider`. |
| rootClassName | string | — | Wrapper class. Use `className` for the `<textarea>` itself. |
| fieldClassName | string | — | Class for the bordered field box. |
TextAreaControl
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| resize | none | vertical | both | vertical |
TextAreaCounter
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| over | 'true' | 'false' | false | |
| disabled | 'true' | 'false' | false |
TextAreaField
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| invalid | 'true' | 'false' | false |
TextAreaFooter
internalTextAreaGrip
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| disabled | 'true' | 'false' | false |