textarea field
A textarea() field stores multi-line string values — anything longer than a
single-line text() field is comfortable holding. It shares text()’s
min/max length semantics and adds a rows option controlling the
rendered height.
Config options
Section titled “Config options”| Option | Type | Default | Description |
|--------|------|---------|-------------|
| label | string | "" | Display label in the admin panel. Inferred from the field key by defineCollection when left empty. |
| required | boolean | false | When false, the field is wrapped in v.optional(…) in the schema and the form allows leaving it empty. |
| defaultValue | string | "" | Pre-filled value shown in the admin form when creating a new document. |
| min | number \| [value: number, error: string] | — | Minimum character length constraint. |
| max | number \| [value: number, error: string] | — | Maximum character length constraint. The character counter below the textarea shows n/max when set. |
| rows | number | 4 | Visible textarea rows in the admin form. |
| index | string \| { name, additionalFields?, draftStatus? } | — | Convex index name, or the object form for a compound index. |
| searchIndex | { name: string, filterFields: string[] } | — | Full-text search index on this field. The field becomes the searchField. |
| description | string | — | Helper text shown below the field input. |
| validate | (props) => Promise<void> \| void | — | Server-only async validation, receives the resolved string value. |
| admin.hidden | boolean | false | Hides the field from the admin edit form entirely. |
| admin.readOnly | boolean | false | Renders the input as non-interactive — value is visible but cannot be changed. |
| admin.position | "main" \| "sidebar" | "main" | Column in the admin edit layout where this field appears. |
| admin.width | string (CSS width) | "100%" | Width of the field inside a row(), e.g. "50%" or "240px". |
| admin.cellAlignment | "left" \| "center" \| "right" | "left" | Horizontal alignment of the value in the list-view table cell. |
| admin.placeholder | string | — | Placeholder text shown when the input is empty. |
| admin.description | string | — | Helper text displayed below the field input. |
| admin.condition | ({ data, siblingData }) => boolean | — | Pure predicate deciding whether the field is shown and validated. A throwing condition counts as met. |
Schema output
Section titled “Schema output”// Optional (required: false — default)bio: v.optional(v.string())
// Required with length constraintsnotes: v.string()
// With a search indexbio: v.string(),.searchIndex("search_bio", { searchField: "bio", filterFields: [] })import { defineCollection, textarea } from "@vexcms/core";
const authors = defineCollection({ slug: "authors", fields: { // Minimal — label inferred from key ("Bio") bio: textarea(),
// Required, length-limited, taller textarea bio: textarea({ required: true, min: 10, max: 500, rows: 8 }),
// Min/max with a custom error message via the [value, error] tuple notes: textarea({ max: [280, "Keep it under 280 characters."] }), },});Admin UI
Section titled “Admin UI”The textarea field renders a <Textarea> sized by rows (default 4).
A right-aligned character counter below the textarea updates as the user
types: n/max when max is configured, the bare count n otherwise.
placeholder and description display inline. In the list-view
table, the value is truncated to one line.