Skip to content

Basic Form

This example shows the smallest useful metadata-driven form in the repository setup.

What It Demonstrates

  • a normal text field
  • generated field paths
  • validation message rendering
  • form state coming from useDynamicForm()

Example

IsDirty: false
Touched: false
Valid: true

// form values:
{}
    

How This Setup Works

This example is split into three small pieces:

  1. BasicFormExample.vue defines the metadata and reads form state with useDynamicForm().
  2. BasicForm.vue mounts DynamicForm and passes in the template plus validation messages.
  3. BasicFormTemplate.vue defines how a field is rendered by mapping the library slots to local UI components.

The metadata in the example only contains labels. The library fills in defaults such as field names and paths, so the two items render as simple text inputs. The template provides the wrapper, input, and error rendering, while useDynamicForm() exposes the live values and meta state shown below the form.

Template Source

vue
export type Metadata = GetMetadataType<typeof metadata>;

const metadata = defineMetadata<
  {
    text: string
  }
>();

BasicFormTemplate.vue is the rendering layer. It defines the metadata contract with defineMetadata(), then uses DynamicFormTemplate slots to wrap each field in FormField, render a TextInput, and show the current validation message.

Form Source

vue
<script setup lang="ts">
import type { DynamicFormSettings, FieldMetadata } from '@bach.software/vue-dynamic-form';
import { DynamicForm } from '@bach.software/vue-dynamic-form';
import BasicFormTemplate from './BasicFormTemplate.vue';

export interface Props {
  metadata: FieldMetadata[]
  settings?: DynamicFormSettings
}

const { metadata, settings: _settings } = defineProps<Props>();

const settings = {
  messages: {
    required: '{field} is required',
    minOccurs: 'At least {min} items required',
    choiceMinOccurs: 'The following fields need to occur at least {min} time(s): {field}',
    minLength: 'The minimum length of {field} is {length}',
    maxLength: 'The maximum length of {field} is {length}',
    length: '{field} must be exactly {length} characters',
    pattern: '{field} does not match the required pattern',
    minInclusive: '{field} must be at least {min}',
    maxInclusive: '{field} must be at most {max}',
    minExclusive: '{field} must be greater than {min}',
    maxExclusive: '{field} must be less than {max}',
    enumeration: '{field} must be one of the allowed values',
    whiteSpace: '{field} contains invalid whitespace (mode: {mode})',
    fractionDigits: '{field} may have at most {digits} decimal place(s)',
    totalDigits: '{field} may have at most {digits} significant digit(s)',
  },
};
</script>

<template>
  <form class="grid grid-cols-2 gap-2">
    <DynamicForm
      :template="BasicFormTemplate"
      :metadata="metadata"
      :settings
    />
  </form>
</template>

BasicForm.vue is the thin bridge between metadata and the template. It receives the metadata array, passes it to DynamicForm, and provides a small settings object so the validation messages are readable in the demo.

Built for schema-driven Vue forms.