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:
BasicFormExample.vuedefines the metadata and reads form state withuseDynamicForm().BasicForm.vuemountsDynamicFormand passes in the template plus validation messages.BasicFormTemplate.vuedefines 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
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
<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.