text field
A text() field stores short, single-line string values. It is the most common
field type in VexCMS — used for titles, names, slugs, URLs, email addresses,
and any other short text value.
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 \| [number, string] | — | Minimum character length constraint. Bare number, or a [value, customError] tuple for a custom error message. |
| max | number \| [number, string] | — | Maximum character length constraint. Bare number, or a [value, customError] tuple. |
| index | string \| { name, additionalFields?, draftStatus? } | — | Convex index name (generates .index(name, [fieldKey])), or the object form for a compound index. See Compound indexes below. |
| 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. |
| 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 | "100%" | CSS width of the field in the edit form (e.g. "50%", "240px"). Meaningful as a child of row(); below a narrow form column every field renders full width regardless. |
| 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 | (props: { data, siblingData }) => boolean | — | Shows the field only while this returns true. A throwing condition counts as met. Hidden fields skip required/validate on the server too. See the Conditional fields & masks guide. |
| admin.mask | string \| string[] \| { mask, storeMasked?, options? } \| false | — | An opt-in use-mask-input pattern, or false to opt out of a project-wide default set via fields.inputMasks.text. See the Conditional fields & masks guide. |
Compound indexes
Section titled “Compound indexes”The object form of index declares a compound index led by the field it’s set on: author’s
index names status as additionalFields, so the generated index covers both fields in order.
author: relationship({ collection: users, index: { name: "by_author_status", additionalFields: ["status"] } })// .index("by_author_status", ["author", "status"])A field-level index wins over a collection-level indexes entry of the same name — every field
setting wins over its collection’s. Pass the collection slug and the field’s own key as generics
to type additionalFields against the collection’s other fields:
author: relationship<"articles", "author">({ collection: users, index: { name: "by_author_status", additionalFields: ["status"] } })For an index that does not lead with a single field’s own key, declare it in the collection’s
indexes instead.
Schema output
Section titled “Schema output”// Optional (required: false — default)title: v.optional(v.string())
// Required with length constraintsslug: v.string()
// With a database indexslug: v.string(),.index("by_slug", ["slug"])
// With a search indextitle: v.string(),.searchIndex("search_title", { searchField: "title", filterFields: ["status"] })import { defineCollection, text } from "@vexcms/core";
const posts = defineCollection({ slug: "posts", fields: { // Minimal — label inferred from key ("Title") title: text(),
// Required slug with length validation and a database index slug: text({ required: true, min: [3, "Slug too short"], max: 100, index: "by_slug" }),
// Author name with a placeholder hint authorName: text({ required: true, admin: { width: "50%", placeholder: "e.g. Jane Smith" }, }),
// Pre-filled default for a canonical URL canonicalUrl: text({ defaultValue: "https://example.com" }), },});Admin UI
Section titled “Admin UI”The text field renders as a single-line <input type="text"> in the edit form.
placeholder and description are displayed inline. In the list-view table, the
raw string value is shown (left-aligned by default). When a field is designated
as useAsTitle, its cell renders as a clickable link to the document edit page.