Custom configuration panels
A host application can replace the built-in property panel for a specific field type without modifying the layer.
The public config-panels prop receives an ordered Vue component registry. The first definition matching the selected field is rendered.
Public contract
ts
import type {
QFormBuilderConfigPanelProps,
QFormBuilderConfigPanelRegistry,
} from '@vevedh/qform-builder-layer/types'Each definition contains:
| Property | Type | Purpose |
|---|---|---|
key | string | Stable panel identifier. |
component | Component | Vue component rendered in the right drawer. |
match | string | (field) => boolean | Matches $formkit, $el, qformKind, configPanel, or a custom predicate. |
priority | number | Optional priority. The highest value wins. |
The panel receives:
ts
export interface QFormBuilderConfigPanelProps {
field: BuilderSchemaField
builderId: string
updateField: (patch: Partial<BuilderSchemaField>) => void
close: () => void
}Use updateField() to apply changes. It keeps the controlled schema, history and autosave synchronized.
Panel component
vue
<script setup lang="ts">
import type { QFormBuilderConfigPanelProps } from '@vevedh/qform-builder-layer/types'
const props = defineProps<QFormBuilderConfigPanelProps>()
const label = computed({
get: () => String(props.field.label || ''),
set: value => props.updateField({ label: value }),
})
const placeholder = computed({
get: () => String(props.field.placeholder || ''),
set: value => props.updateField({ placeholder: value }),
})
</script>
<template>
<q-list separator>
<q-item-label header>Business configuration</q-item-label>
<q-item>
<q-item-section class="q-gutter-md">
<q-input v-model="label" filled dense label="Label" />
<q-input v-model="placeholder" filled dense label="Placeholder" />
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-btn flat no-caps label="Close" @click="close" />
</q-item-section>
</q-item>
</q-list>
</template>Register it in FormBuilder
vue
<script setup lang="ts">
import { markRaw } from 'vue'
import type { QFormBuilderConfigPanelRegistry } from '@vevedh/qform-builder-layer/types'
import BusinessTextFieldPanel from '~/components/forms/BusinessTextFieldPanel.vue'
const configPanels: QFormBuilderConfigPanelRegistry = [
{
key: 'business-text-field',
component: markRaw(BusinessTextFieldPanel),
match: field => field.$formkit === 'q-input' && field.inputType === 'text',
priority: 100,
},
]
</script>
<template>
<FormBuilder builder-id="business-form" :config-panels="configPanels" />
</template>Best practices
- Use a stable and unique
key. - Wrap components with
markRaw()so Vue does not make the component definition reactive. - Never mutate
fielddirectly; useupdateField(). - Keep business rules and network calls in a store or repository.
- Use a narrow predicate to avoid replacing unrelated field panels.