32
FormForge Client

FormForgeRenderer

Render, navigate, validate, and submit FormForge forms in internal or controlled mode.

FormForgeRenderer renders and can submit a FormForge form.

The component resolves two explicit external paths internally:

  • external model mode (modelValue provided)
  • external schema mode (schema provided)

Internal mode

Pass only a form key and let the component manage load, validation, navigation, and submit.

<FormForgeRenderer :form-key="'contact'" />

Standalone hybrid mode (form-key + v-model)

You can combine form-key with v-model (modelValue) to read form data in real time without final internal submission.

<script setup lang="ts">
const formData = ref<Record<string, unknown>>({})
</script>

<template>
  <FormForgeRenderer
    form-key="my-form"
    v-model="formData"
  />
</template>

When modelValue is provided:

  • the renderer emits update:modelValue on every field change
  • form submit does not trigger backend submission from the renderer
  • submit buttons are hidden by default
  • internal submit success and error UI states are hidden

This mode is designed for external state management and custom submission flows.

showSubmit uses tri-state behavior:

  • omit show-submit to hide submit buttons automatically when using v-model
  • use :show-submit="true" to show the submit button explicitly
  • use :show-submit="false" to keep it hidden explicitly

Controlled mode

Use composables and pass model and schema manually.

<FormForgeRenderer
  :schema="form.schema"
  :model-value="form.state"
  :zod-schema="form.zodSchema"
  @update:model-value="form.replaceState"
/>

Progress and navigation

FormForgeRenderer can show the current block progress and the built-in navigation buttons.

  • pagination="auto" keeps the default paginated navigation between visible blocks
  • pagination="none" renders all visible fields from all blocks in one view
  • showProgress renders a UProgress bar when more than one block is visible
  • showProgress is ignored when pagination="none"
  • showSubmit controls the submit button; it defaults to hidden with v-model and visible otherwise
  • Previous and Next appear when the renderer can navigate between blocks
  • simulation keeps navigation visible in preview-style usage
  • previewPageKey locks the renderer to a single block, which is useful for playground previews
<FormForgeRenderer
  form-key="contact"
  :show-progress="true"
  :simulation="true"
  :preview-page-key="selectedPageKey"
/>

Use pagination="none" when all fields should appear on a single screen:

<FormForgeRenderer
  form-key="contact"
  pagination="none"
  :show-progress="true"
/>

In this mode, navigation controls and the progress indicator are hidden. Validation still covers the full form, the submitted payload remains unchanged, and conditional rules continue to work across blocks.

Validation API (standalone and external model)

FormForgeRenderer exposes validation helpers through the component ref:

  • validate(options?)
  • validateField(name)
  • clearErrors(path?)
  • getErrors(path?)
<script setup lang="ts">
const renderer = ref<InstanceType<typeof FormForgeRenderer> | null>(null)

async function runValidation(): Promise<void> {
  const result = await renderer.value?.validate()
  if (!result?.valid) {
    console.log(renderer.value?.getErrors())
  }
}
</script>

<template>
  <FormForgeRenderer ref="renderer" form-key="my-form" />
</template>

Validation props:

  • validateOn
  • validateOnBlur

In external v-model integrations, blur-based validation is handled explicitly per field (focusout path) for more predictable standalone behavior.

Integrating in a custom parent form

When FormForge data is embedded in a parent form, block parent submit until renderer validation passes.

<script setup lang="ts">
import { z } from 'zod'

const renderer = ref<InstanceType<typeof FormForgeRenderer> | null>(null)
const formData = ref<Record<string, unknown>>({})

const parentSchema = z.object({
  title: z.string().min(1),
  data: z.record(z.string(), z.unknown())
})

async function onParentSubmit(): Promise<void> {
  const rendererResult = await renderer.value?.validate()
  if (!rendererResult?.valid) {
    return
  }

  // continue with your external submit flow
}
</script>

<template>
  <form @submit.prevent="onParentSubmit">
    <FormForgeRenderer
      ref="renderer"
      form-key="my-form"
      v-model="formData"
      :validate-on-blur="true"
    />
  </form>
</template>

Use an object schema for embedded FormForge payloads (z.record(...)), not z.string().