Components

Form Fields

Dynamic form field system powered by TanStack Form. 49 field types with automatic dispatch via DynamicFormField.

Client Only

Installation

pnpm dlx @docyrus/cli add @docyrus/ui-form-fields
UI Primitives(21 components)
npx shadcn@latest add avatar badge button calendar checkbox command dialog field input label phone-input popover scroll-area select separator sortable switch tabs textarea time-picker tooltip
Plate Editor(53 components)
npx shadcn@latest add @plate/ai-kit @plate/ai-toolbar-button @plate/align-kit @plate/align-toolbar-button @plate/autoformat-kit @plate/basic-blocks-kit @plate/basic-marks-kit @plate/block-menu-kit @plate/block-placeholder-kit @plate/callout-kit @plate/code-block-kit @plate/column-kit @plate/comment-kit @plate/comment-toolbar-button @plate/date-kit @plate/discussion-kit @plate/dnd-kit @plate/editor @plate/editor-base-kit @plate/editor-static @plate/emoji-kit @plate/emoji-toolbar-button @plate/equation-toolbar-button @plate/exit-break-kit @plate/fixed-toolbar @plate/floating-toolbar @plate/font-color-toolbar-button @plate/font-kit @plate/font-size-toolbar-button @plate/history-toolbar-button @plate/indent-toolbar-button @plate/insert-toolbar-button @plate/line-height-kit @plate/line-height-toolbar-button @plate/link-kit @plate/link-toolbar-button @plate/list-kit @plate/list-toolbar-button @plate/mark-toolbar-button @plate/math-kit @plate/mention-kit @plate/mode-toolbar-button @plate/more-toolbar-button @plate/slash-kit @plate/suggestion-kit @plate/suggestion-toolbar-button @plate/table-kit @plate/table-toolbar-button @plate/toc-kit @plate/toggle-kit @plate/toggle-toolbar-button @plate/toolbar @plate/turn-into-toolbar-button
Required Packages(8 packages)
pnpm add @tanstack/react-form date-fns react-day-picker platejs react-email-editor react-querybuilder @uiw/react-codemirror @uiw/codemirror-extensions-langs

Usage

import { useForm } from '@tanstack/react-form';
import { DynamicFormField } from '@docyrus/ui/components/form-fields';
import type { IField, EnumOption } from '@docyrus/ui/components/form-fields';

const fields: IField[] = [
  { id: '1', name: 'Full Name', slug: 'full_name', type: 'field-text' },
  { id: '2', name: 'Priority', slug: 'priority', type: 'field-select' },
  { id: '3', name: 'Active', slug: 'is_active', type: 'field-switch' },
];

const enumOptions: EnumOption[] = [
  { id: 'low', name: 'Low', color: '#22c55e' },
  { id: 'medium', name: 'Medium', color: '#f59e0b' },
  { id: 'high', name: 'High', color: '#ef4444' },
];

function MyForm() {
  const form = useForm({
    defaultValues: { full_name: '', priority: '', is_active: false },
    onSubmit: ({ value }) => console.log(value),
  });

  return (
    <form onSubmit={(e) => { e.preventDefault(); form.handleSubmit(); }}>
      {fields.map((field) => (
        <DynamicFormField
          key={field.id}
          field={field}
          form={form}
          enumOptions={field.type === 'field-select' ? enumOptions : undefined}
        />
      ))}
    </form>
  );
}

Individual Field Import

You can import individual field components to reduce bundle size:

import { TextFormField } from '@docyrus/ui/components/form-fields/text-form-field';
import { SelectFormField } from '@docyrus/ui/components/form-fields/select-form-field';
import { SwitchFormField } from '@docyrus/ui/components/form-fields/switch-form-field';

Field Types

Text & Content

TypeComponentDescription
field-textTextFormFieldSingle-line text input
field-textareaTextareaFormFieldMulti-line text area
field-emailEmailFormFieldEmail input with validation
field-urlUrlFormFieldURL input with https:// placeholder
field-phonePhoneFormFieldPhone number with mask input
field-colorColorFormFieldColor picker with hex input
field-iconIconFormFieldIcon picker (Docyrus icon set)

Numbers

TypeComponentDescription
field-numberNumberFormFieldNumeric input
field-moneyMoneyFormFieldMoney input with currency symbol
field-percentPercentFormFieldPercentage input (0-100)
field-durationDurationFormFieldDuration picker grid via Duration Select
field-ratingRatingFormFieldStar rating (1-5)
field-currencyCurrencyCodeFormFieldCurrency code selector

Selection

TypeComponentDescription
field-selectSelectFormFieldSingle select with color/icon indicators
field-multiSelectMultiSelectFormFieldMulti-value select
field-tagSelectTagSelectFormFieldTag-based multi-select
field-radioGroupRadioGroupFormFieldRadio button group
—CheckboxGroupFormFieldInline multi-select with radio-group visuals — array value, default and card variants, columnCount 1–4
field-enumEnumFormFieldEnum dropdown (slug-based values)
field-statusStatusFormFieldStatus select with description + follow-up
field-approvalStatusApprovalStatusFormFieldApproval workflow status

Date & Time

TypeComponentDescription
field-dateDateFormFieldDate picker with calendar popover
field-dateTimeDateTimeFormFieldCombined date and time picker
field-timeTimeFormFieldTime picker
field-dateRangeDateRangeFormFieldDate range with start/end

Toggle

TypeComponentDescription
field-checkboxCheckboxFormFieldCheckbox with horizontal layout
field-switchSwitchFormFieldToggle switch with horizontal layout

Relation & Users

TypeComponentDescription
field-relationRelationFormFieldRelated record lookup
field-userSelectUserSelectFormFieldSingle user selector
field-userMultiSelectUserMultiSelectFormFieldMulti-user selector
field-locationSelectLocationSelectFormFieldLocation/address picker with Google Maps when VITE_GOOGLE_MAPS_API_KEY is configured

Rich Content

LocationSelectFormField automatically upgrades to the map-based picker in Vite apps when VITE_GOOGLE_MAPS_API_KEY is available. Without that variable, it falls back to manual address and coordinate inputs.

TypeComponentDescription
field-docEditorDocEditorFormFieldRich text editor (Plate.js) with preset-based plugin system
field-htmlEditorHtmlEditorFormFieldWYSIWYG HTML editor (Plate.js) with export/import support
field-emailEditorEmailEditorFormFieldEmail template editor (Unlayer)
field-codeEditorCodeEditorFormFieldCode editor (CodeMirror 6) with syntax highlighting and dark/light theme
field-adaptiveCardAdaptiveCardFormFieldDialog-based Adaptive Card Designer — visual authoring of Microsoft Adaptive Card payloads

Data & Structure

TypeComponentDescription
field-fileFileFormFieldFile upload
field-imageImageFormFieldImage upload with preview
field-avatarAvatarFieldAvatar selector
field-taskListTaskListFormFieldChecklist / task list
field-schemaRepeaterSchemaRepeaterFormFieldRepeater with drag & drop, collapsible rows, schema or key-value mode
field-jsonSchemaJsonSchemaFormFieldDialog-based JSON Schema Designer — drag-and-drop tree + JSON tab
field-jsonataJsonataFormFieldDialog-based JSONata Editor — write, autocomplete and live-test a JSONata expression
field-queryBuilderQueryBuilderFormFieldQuery builder
field-dynamicDynamicConfigFormFieldDynamic configuration field

API Reference

DynamicFormField

Dispatcher component that renders the correct field based on field.type.

<DynamicFormField
  field={fieldConfig}
  form={form}
  enumOptions={options}
  required
  disabled={false}
  className="my-field"
/>

DocEditorFormField

Rich text editor with preset-based plugin and toolbar system.

import { DocEditorFormField } from '@docyrus/ui/components/form-fields/doc-editor-form-field';
import type { DocEditorPreset } from '@docyrus/ui/components/form-fields/doc-editor-form-field';

<DocEditorFormField field={fieldConfig} form={form} preset="rich" />
PropTypeDefaultDescription
presetDocEditorPreset'default'Editor preset level

Presets

PresetPluginsToolbar
defaultParagraphs, headings, lists, inline marks, link, autoformatFloating only (marks + turn into + link)
rich+ table, code block, callout, toggle, emoji, font, alignFixed + Floating
full+ columns, math, date, ToC, comments, suggestions, DnD, block menuFixed + Floating (all buttons)

Preset Dependencies

Each preset requires additional packages beyond the base platejs dependency:

PresetAdditional Packages
default@platejs/autoformat @platejs/link @platejs/floating @platejs/list
rich+ @platejs/code-block @platejs/table @platejs/callout @platejs/toggle @platejs/basic-styles @platejs/emoji @platejs/indent @emoji-mart/data lowlight
full+ @platejs/layout @platejs/math @platejs/date @platejs/toc @platejs/comment @platejs/suggestion @platejs/selection @platejs/dnd react-dnd react-dnd-html5-backend

HtmlEditorFormField

WYSIWYG HTML editor powered by Plate.js that stores value as an HTML string. Includes the same rich formatting toolbar as DocEditorFormField (bold, italic, headings, lists, tables, etc.) plus built-in export and import buttons.

import { HtmlEditorFormField } from '@docyrus/ui/components/form-fields/html-editor-form-field';

<HtmlEditorFormField field={fieldConfig} form={form} preset="rich" />
PropTypeDefaultDescription
fieldIField—Field configuration
formany—TanStack Form instance
disabledbooleanfalseDisable editing
classNamestring—Additional CSS class
presetDocEditorPreset'rich'Plate.js preset level

Data format: Unlike DocEditorFormField (which stores Plate JSON), HtmlEditorFormField stores the value as an HTML string. Plate content is serialized to HTML via serializeHtml and deserialized back via editor.api.html.deserialize.

Export: Built-in export toolbar button supports HTML, PDF, Image, and Markdown formats.

Import: Built-in import toolbar button supports HTML and Markdown file import.

CodeEditorFormField

Code editor powered by CodeMirror 6 with syntax highlighting, bracket matching, and autocompletion. Supports dark/light theme via useDocyTheme.

import { CodeEditorFormField } from '@docyrus/ui/components/form-fields/code-editor-form-field';

<CodeEditorFormField field={fieldConfig} form={form} language="python" />
PropTypeDefaultDescription
fieldIField—Field configuration
formany—TanStack Form instance
disabledbooleanfalseDisable editing
classNamestring—Additional CSS class
languageLanguageName'tsx'CodeMirror language ('tsx', 'python', 'json', 'css', 'sql', 'go', 'rust', etc.)
basicSetupBasicSetupOptionsSee belowCodeMirror basicSetup overrides
minHeightstring'200px'Editor minimum height

Default basicSetup: Line numbers, fold gutter, bracket matching, close brackets, autocompletion, active line highlight, selection match highlight, tab size 2.

Language support: 50+ languages via @uiw/codemirror-extensions-langs. Dark/light theme auto-detected via useDocyTheme.

SchemaRepeaterFormField

Repeatable form rows with drag & drop reordering, collapsible items, and dual mode support. Inspired by Filament Repeater.

Schema mode — pass schema prop with IField[] to render sub-fields per row:

import { SchemaRepeaterFormField } from '@docyrus/ui/components/form-fields/schema-repeater-form-field';

<SchemaRepeaterFormField
  field={fieldConfig}
  form={form}
  schema={[
    { id: '1', name: 'Name', slug: 'name', type: 'field-text' },
    { id: '2', name: 'Role', slug: 'role', type: 'field-select' }
  ]}
  schemaEnumOptions={{ role: [{ id: 'admin', name: 'Admin' }, { id: 'editor', name: 'Editor' }] }}
/>

Key-value mode — omit schema prop for simple key-value pairs:

<SchemaRepeaterFormField field={fieldConfig} form={form} />
PropTypeDefaultDescription
fieldIField—Field configuration
formany—TanStack Form instance
disabledbooleanfalseDisable editing
classNamestring—Additional CSS class
schemaIField[]—Sub-field definitions. If omitted, key-value mode.
schemaEnumOptionsRecord<string, EnumOption[]>—Enum options keyed by sub-field slug
maxItemsnumber—Maximum number of items
minItemsnumber0Minimum number of items
collapsiblebooleantrueWhether items can be collapsed
defaultCollapsedbooleanfalseWhether items start collapsed
addLabelstring'Add item'Add button label
cloneablebooleanfalseWhether items can be cloned
itemLabel(item, index) => string#indexDynamic item label

FieldMappingFormField

Wrapper that provides four value sources for any form field: fixed, field mapping, template (with @mention), and formula. The active tab is auto-detected from the stored value prefix. If only one tab is enabled via modes, the wrapper renders without the tab chrome.

import { FieldMappingFormField } from '@docyrus/ui/components/form-fields/field-mapping-form-field';
import type { AvailableField } from '@docyrus/ui/components/form-fields/field-mapping-form-field';

const availableFields: AvailableField[] = [
  { name: 'user.name', label: 'User Name', type: 'text' },
  { name: 'user.email', label: 'User Email', type: 'email' },
  { name: 'project.title', label: 'Project Title', type: 'text' }
];

<FieldMappingFormField
  field={fieldConfig}
  form={form}
  availableFields={availableFields}>
  <TextFormField field={fieldConfig} form={form} />
</FieldMappingFormField>

Value format — the wrapper encodes the active mode as a prefix in the form value:

ModePrefixExample value
fixed(none)Hello world
field-mapping#FIELD=#FIELD=user.name
template#TEMPLATE=#TEMPLATE=Hello @user.name!
formula#FORMULA=#FORMULA=user.age > 18 ? "adult" : "minor"
PropTypeDefaultDescription
fieldIField—Field configuration
formany—TanStack Form instance
disabledbooleanfalseDisable all tabs
requiredbooleanfalseShow required indicator on label
classNamestring—Additional CSS class
availableFieldsAvailableField[][]Selectable fields for mapping/template/formula tabs
modesMappingTab[]['fixed', 'field-mapping', 'template', 'formula']Which tabs to show
childrenReactNode—Form field component rendered in the Fixed tab

AvailableField:

FieldTypeDescription
namestringSlug used in the encoded value (e.g. user.name)
labelstringHuman-readable label shown in dropdowns and mention spans
typestringField data type
iconstringOptional icon name

Template mentions — inside the Template tab, type @ to open a searchable picker. Inserted mentions render as styled spans with data-field-name attributes. The editor uses strict allowlist parsing (text, <br>, and data-field-name spans only) to prevent XSS when reloading stored HTML.

CheckboxGroupFormField

Inline multi-select that shares its visual language with RadioGroupFormField (square checkbox indicators) and stores the selected option ids as a string[] like TagSelectFormField. Good fit for a small, fixed set of options where the dropdown popover of TagSelect would feel heavy.

import { CheckboxGroupFormField } from '@docyrus/ui/components/form-fields/checkbox-group-form-field';

<CheckboxGroupFormField
  field={fieldConfig}
  form={form}
  enumOptions={DEPARTMENT_OPTIONS}
  variant="card"
  columnCount={2}
/>
PropTypeDefaultDescription
fieldIField—Field configuration. The form value at field.slug must be string[].
formany—TanStack Form instance
enumOptionsEnumOption[][]Selectable options. Supports icon, color, and description.
variant'dropdown' | 'card'—'card' renders bordered cards with description support. Any other value renders the compact inline layout.
columnCount1 | 2 | 3 | 41Number of grid columns, responsive at sm / lg breakpoints.
disabledbooleanfalseDisable all options
requiredbooleanfalseShow red asterisk on label
classNamestring—Additional CSS class on the outer Field

Visual variants

VariantLayoutUse case
defaultCompact inline checkbox + label, aligns with RadioGroup defaultShort labels, dense layouts
cardBordered card with icon/color + label + description, highlights on checkRich choices with descriptions or imagery

DocyrusFormFieldProps

All form field components share this interface:

PropTypeDefaultDescription
fieldIField—Field configuration from the data source
formany—TanStack Form instance (useForm() result)
disabledbooleanfalseWhether the field is disabled
requiredbooleanfalseShow red asterisk on label
classNamestring—Additional CSS class
enumOptionsEnumOption[][]Options for select-based fields
appSlugstring—App slug for dynamic enum loading
dataSourceSlugstring—Data source slug for dynamic enum loading

IField

FieldTypeDescription
idstringUnique field identifier
namestringDisplay label
slugstringForm value key (used as form.Field name)
typeIFieldTypeField type — determines which component renders
defaultValuestring | nullDefault value
validationsstring[] | nullValidation rules
readOnlyboolean | nullRead-only flag
fieldActionsFieldAction[] | nullImperative actions triggered when this field's value changes. Evaluated by useDocyrusFormView's field-actions engine.
customValidationsCustomValidationRule[] | nullJSONata-based validation rules evaluated on submit. Each rule has expression (must return true to pass) and message (shown on failure). Rules are evaluated in order — first failure wins. Can also be injected at runtime via fieldLayout[slug].customValidations.

EnumOption

FieldTypeDescription
idstringOption identifier
namestringDisplay label
colorstringColor indicator (hex)
iconstringDocyrus icon name
slugstringSlug value (used by EnumFormField)
sort_ordernumberDisplay order

Field Action Types

These types define the imperative action system used by useDocyrusFormView to react to field-value changes.

TypeDescription
FieldActionA named trigger with triggerType: 'onFieldChange' and an ordered list of FieldActionBlock[].
FieldActionBlockA named block with if / else-if / else branches (conditionalItems, elseActions) and unconditionalActions that always run.
FieldActionBlockItemOne conditional branch: a condition (JSONata string or QB rule group) and the actions to run when it matches.
FieldActionConditionSame format as ComputedBooleanFormula — JSONata string, QB RuleGroupType, or null (always-true).
FieldActionStepDiscriminated union of imperative commands: setFieldValue, setFieldValues, clearFieldValue, showField, hideField, setFieldRequired, setFieldDisabled, setFieldReadOnly.
FieldActionPropertyOverridesAccumulated per-field overrides produced by action execution: hidden, required, disabled, readOnly.

On this page