Skip to content

Field model

Field configuration

Use these config keys with the source files and examples that read them.

text, email, password, url, tel, textarea, number

select, radio, checkbox, switch, date, slider, rating

phone, file, array, object, multiSelect, combobox, autocomplete

multiCombobox, color, duration, location, masked

aliases: multiselect, multicombobox, colorPicker, maskedInput

Field configuration

FormedibleFieldConfig defines the public keys. normalizeFieldConfig fills runtime defaults before the registry chooses a renderer.

  • Source: packages/formedible/src/lib/formedible/types.ts lines 243-313 define the top-level field keys and nested config objects.
  • Renderer lookup: packages/formedible/src/components/formedible/fields/field-registry.tsx maps normalized field types to components.
  • Alias behavior is tested in tests/formedible/advanced-fields.test.tsx under “legacy alias fields render field-specific compatibility UI”.
PropertyTypeDefaultDescription
name
string
requiredTanStack Form field path. Nested paths are joined by the renderer; see field-path.ts and object-field.tsx.
type
FormedibleFieldType
textRenderer key. normalize-field-config.ts maps multiselect, multicombobox, colorPicker, and maskedInput aliases before registry lookup.
label
ReactNode
—Rendered by field-wrapper.tsx. Dynamic text tokens are resolved in use-formedible.tsx.
description
ReactNode
—Field help copy rendered below the label by field-wrapper.tsx, separate from validation errors.
placeholder
string
—Passed to renderers that read a placeholder: text, textarea, number, password, phone, autocomplete, combobox-style fields, and primitive array items. Tokens resolve in use-formedible.tsx.
dynamicPlaceholder
boolean
—Declared on the type for compatibility. Current dynamic placeholder behavior comes from token resolution on placeholder.
disabled
boolean
falseSet per field or through the form-level disabled option; normalization fills the default.
required
boolean
falseMarks the label/control as required and also feeds Formedible’s built-in required-value validator before schema, validation, inlineValidation, asyncValidation, min, max, and related validators.
className / inputClassName
string
—className styles the field shell; inputClassName is passed by input renderers that expose an inner control class.
page / tab / section
number / string / FormedibleFieldSection
—Layout metadata used by use-multi-page.ts, use-form-tabs.ts, and section rendering in use-formedible.tsx.
conditional
string | (values) => boolean
—String paths are truthy checks; functions receive current form values or local object-array item values.
options
FormedibleFieldOption[] | (values) => FormedibleFieldOption[]
[]Used by select, radio, multiSelect, combobox, autocomplete fallback, and multiCombobox through advanced-field-utils.ts.
optionSets
Record<string, FormedibleFieldOption[]>
—Typed compatibility metadata. Built-in field renderers read options or nested autocompleteConfig.options instead.
datalist
FormedibleFieldOption[]
—Native datalist suggestions for text-field.tsx and number-field.tsx.
arrayConfig / objectConfig / nestedFields
nested config
—Structural config for array-field.tsx and object-field.tsx. objectConfig.fields wins over nestedFields for object fields.
min / max / step
number
—Top-level number bounds used by number-field.tsx and as slider fallbacks.
rows / maxLength
number
—Top-level textarea settings. They take priority over textareaConfig.rows and textareaConfig.maxLength.
mask / maskedInputConfig
FormedibleMaskedInputMask / nested config
—Consumed by masked-field.tsx. type: "maskedInput" normalizes to masked before lookup.
textareaConfig / passwordConfig / numberConfig
nested config
—Consumed by textarea-field.tsx, password-field.tsx, and number-field.tsx. Top-level rows, maxLength, min, max, and step take priority where supported.
dateConfig / sliderConfig / ratingConfig / fileConfig
nested config
—Advanced renderer config defined in types.ts and consumed by the matching field component.
multiSelectConfig / comboboxConfig / autocompleteConfig / multiComboboxConfig
nested config
—Search, creation, max-selection, and autocomplete settings consumed by the matching option renderers.
colorConfig / phoneConfig / durationConfig / locationConfig
nested config
—Advanced renderer config defined in types.ts and consumed by the matching field component.
help
ReactNode | FormedibleHelpConfig
—Supplementary help rendered by field-wrapper.tsx when present.
validation / inlineValidation
validator config
—Field-level validation inputs read by buildFieldValidators.
emailConfig
never
unsupportedIntentionally unsupported; use schema or validation for email-specific rules.
component / wrapper
FormedibleFieldComponent / FormedibleFieldWrapper
—Per-field render escape hatches used by field-renderer.tsx before registry fallback and globalWrapper.
custom props
unknown
—Retained for custom renderers and metadata. Built-in behavior should use supported config keys above.

Text inputs

Text-like fields share the same base config. Add renderer-specific config only when the field needs it.

  • Text, email, url, and tel share text-field.tsx; datalist renders native suggestions there and in number-field.tsx.
  • Textarea config: { textareaConfig: { rows: 4, maxLength: 500, resize: "vertical", showWordCount: true } }. See textarea-field.tsx and tests/formedible/basic-fields.test.tsx.
  • Password config: { passwordConfig: { showToggle: true, strengthMeter: true, minStrength: 3 } }. See password-field.tsx.
  • Masked config: { type: "masked", mask: "999-99-9999" } or { type: "maskedInput", maskedInputConfig: { mask: "000-00-0000" } }. See masked-field.tsx and tests/formedible/advanced-fields.test.tsx.

Selection fields

Selection fields use options; checkbox and switch use booleans. String options are normalized before render.

  • Select config: { name: "role", type: "select", options: [{ value: "qa", label: "QA" }] }. See apps/web/src/components/docs/examples/array-fields-form.tsx.
  • Radio config: { name: "destination", type: "radio", options: ["beach", "mountains", "city"] }. See tests/formedible/advanced-fields.test.tsx vacationFlowFields.
  • Checkbox and switch render boolean controls from checkbox-field.tsx and switch-field.tsx; tests/formedible/basic-fields.test.tsx covers their primitive imports and default boolean value path.
  • Dependent options use a function: options: (values) => values.plan === "team" ? ["audit", "roles"] : ["profile"]. The resolver is resolveFieldOptions in advanced-field-utils.ts.

Advanced inputs

Advanced fields keep settings in nested config objects. Use the config that matches the field type.

  • Live example: /docs/examples?example=advanced-fields, id advanced-fields, source apps/web/src/components/docs/examples/advanced-field-types-form.tsx.
  • Rating config: { ratingConfig: { max: 5, allowHalf: true, icon: "star", size: "lg", showValue: true } }. Source: rating-field.tsx.
  • Slider config: { sliderConfig: { min: 0, max: 100, step: 5, valueLabelSuffix: "%", showValue: true, marks: [{ value: 50, label: "Mid" }] } }. Source: slider-field.tsx and tests/formedible/advanced-fields.test.tsx.
  • Color, phone, duration, location, date, and file keys are defined in types.ts lines 640-788 and consumed by their matching field files.

Multi-value fields

multiSelect, combobox, autocomplete, and multiCombobox share the option model. Their nested configs control search, creation, limits, and autocomplete loading.

  • multiSelect config: { multiSelectConfig: { searchable: true, creatable: true, maxSelections: 3, placeholder: "Pick skills" } }. Source: multi-select-field.tsx.
  • combobox config: { comboboxConfig: { searchable: true, searchPlaceholder: "Search countries", noOptionsText: "No match" } }. Source: combobox-field.tsx.
  • autocomplete config: { autocompleteConfig: { options: ["France"], minChars: 1, debounceMs: 300, allowCustom: false } }. Source: autocomplete-field.tsx; stale async behavior is tested in tests/formedible/advanced-fields.test.tsx.
  • Example pointers: contact uses combobox and multiCombobox in apps/web/src/components/docs/examples/contact-form.tsx; survey uses multiSelect in apps/web/src/components/docs/examples/survey-form.tsx.

Structural fields

array and object fields render child fields with nested paths. objectConfig.fields wins over nestedFields for object fields.

  • Working link: /docs/examples?example=arrays, id arrays, source apps/web/src/components/docs/examples/array-fields-form.tsx.
  • Object arrays use { arrayConfig: { itemType: "object", minItems: 1, maxItems: 10, sortable: true, defaultValue: { name: "", email: "" }, objectConfig: { layout: "grid", columns: 2, fields: [{ name: "name", type: "text", label: "Name" }, { name: "email", type: "email", label: "Email" }] } } }. Source: array-field.tsx.
  • Scalar arrays use { arrayConfig: { itemType: "email", itemPlaceholder: "contact@company.com", defaultValue: "" } }. itemLabel, addButtonLabel, removeButtonLabel, and itemPlaceholder are consumed by array-field.tsx.
  • Object fields use objectConfig.fields first, then nestedFields. Source: object-field.tsx; nested behavior is covered in tests/formedible/nested-fields.test.tsx.

Dynamic behavior

Dynamic behavior lives in field config. Conditions, option functions, and text tokens resolve from current values.

  • Visibility config: { conditional: "billingAddress" } checks a path; { conditional: (values) => values.destination === "beach" } runs against current values.
  • Dynamic text uses tokens in label, description, placeholder, page title, page description, and section copy. See resolveDynamicText in dynamic-text.ts and use-formedible.tsx.
  • Live examples: /docs/examples?example=conditional-pages for page-level conditions and /docs/examples?example=conditional-object-array for conditions inside array object items.
  • Tests: tests/formedible/advanced-fields.test.tsx checks dynamic labels, conditional car fields, and page copy; tests/formedible/section-rendering.test.tsx checks section output.

Custom rendering

Custom rendering has a fixed order: field component, defaultComponents, then registry. Field wrapper wraps first, then globalWrapper.

  • Per-field component wins first through the component key. Then defaultComponents[renderConfig.type], then getFieldComponent(type) from field-registry.tsx.
  • Per-field wrapper wraps a single field; globalWrapper wraps rendered fields from useFormedible options. Both receive fieldConfig, field, and children.
  • The shared code card on this page uses docsCodeExamples id field-registry-extension from apps/web/src/features/docs/code-examples.ts.
  • The advanced-fields live example shows sliderConfig.visualizationComponent for custom slider visuals without replacing the whole slider renderer.

Customize the copied registry

The registry is copied into your app, so customize supported field types by editing the local mapping directly.

import type { ReactNode } from 'react';

import { NumberField } from '@/components/ui/formedible/fields/number-field';
import { TextField } from '@/components/ui/formedible/fields/text-field';
import type { FormedibleFieldRenderProps, FormedibleFormValues, NormalizedFieldType } from '@/components/ui/formedible/lib/types';

type FieldComponent = <TFormValues extends FormedibleFormValues>(props: FormedibleFieldRenderProps<TFormValues>) => ReactNode;

const fieldRegistry: Partial<Record<NormalizedFieldType, FieldComponent>> = {
  number: NumberField,
  text: TextField,
};

export function getFieldComponent<TFormValues extends FormedibleFormValues>(
  type: NormalizedFieldType,
): (props: FormedibleFieldRenderProps<TFormValues>) => ReactNode {
  return fieldRegistry[type] ?? TextField;
}

Formedible

TanStack Form, shadcn/ui, Zod