Custom renderers
Every property gets a field that matches its type: a text input for string, a number input for number, a switch for boolean, and so on. Set renderer on a property to choose a different component.
Built-in renderers
Some fields have an alternative in the module. Use the component name, with the S prefix:
{
"type": "object",
"properties": {
"notes": {
"title": "Notes",
"type": "string",
"renderer": "STextarea"
},
"internalId": {
"type": "string",
"renderer": "none"
}
}
}
STextarearenders a string as a multi-line text area.SSelectrenders a string with anenumas a select menu.nonerenders nothing. The value stays in the form data.
The prefix follows the prefix module option. With prefix: 'My', use MyTextarea.
Your own component
renderer also accepts the name of a component from your app. The component is looked up by name at runtime, so it must be registered globally. Put it in components/global/, or name the file *.global.vue:
<script lang="ts" setup>
defineProps<{
id: string
title?: string
description?: string
isRequired: boolean
}>()
const value = defineModel<string>({ default: '#00dc82' })
</script>
<template>
<UFormField :name="id" :label="title" :description="description" :required="isRequired">
<UColorPicker v-model="value" />
</UFormField>
</template>
{
"type": "object",
"properties": {
"brandColor": {
"title": "Brand color",
"type": "string",
"renderer": "ColorField"
}
}
}
Set name on UFormField to the id prop, so validation errors for this property show up on your field.
Props
A renderer receives every keyword of its property's schema as a prop, such as title, description, properties and required. It also receives:
| Prop | Description |
|---|---|
id | The property's dot path in the form value, like guardian.email. Use it as the form field name. |
modelValue | The property's value. Emit update:modelValue to change it, or use defineModel(). |
isRequired | Whether the parent object lists this property in required. |
validateFields | (fields: string[]) => Promise<boolean>. Validates the given fields by dot path and runs custom validation for them. Only a renderer on the root schema receives it. |
Rendering nested fields
A renderer for an object can render its children with the module's own components. Use SComponent to render a property just as the form would:
<script lang="ts" setup>
defineProps<{
id: string
title?: string
properties: Record<string, Record<string, unknown>>
required: string[]
}>()
const value = defineModel<Record<string, unknown>>({ required: true })
</script>
<template>
<UCard>
<template #header>{{ title }}</template>
<SComponent
v-for="(child, key) in properties"
:key="key"
v-bind="child"
:id="id ? `${id}.${key}` : key"
:model-value="value[key]"
:is-required="required.includes(key)"
@update:model-value="childValue => (value = { ...value, [key]: childValue })"
/>
</UCard>
</template>
For a full example, see the multi-step form in the demo. Its MultiStage renderer shows one child object per step and calls validateFields before moving to the next one.