← Blog
3 Aug 2026Vueformsform schemasgenerated UIJSON Schema

Generated Form Layouts: A Practical Guide for Vue Applications

Learn how to build generated form layouts in Vue with schemas, reusable components, responsive structure, validation, and DOM Studio.

Generated Form Layouts: A Practical Guide for Vue Applications

Generated Form Layouts: A Practical Guide for Vue Applications

Generated form layouts turn a typed definition into a usable interface: fields, groups, responsive structure, validation, and submission state. We use them when forms must change often, come from server-side metadata, or need to stay consistent across many workflows.

In this guide, we will build a reliable generated-form approach in Vue with DOM Studio. The result is not a rigid form builder. It is an editable system where the data contract stays portable, while components and layout remain under product-team control.

Table of contents

Before you start

You need a Vue application, DOM Studio’s Vue package, a form model, and a schema source. That source might be a hand-authored object, JSON Schema, a Zod-like schema, a CMS field model, an OpenAPI request body, or database metadata.

We recommend separating three concerns from the beginning:

  1. Definition: field types, labels, constraints, components, and layout hints.
  2. Values: only the data the user enters.
  3. Renderer: the Vue components that turn the definition into an interface.

This separation keeps generated form layouts maintainable. It also lets us replace a component, reorganize a section, or add a new validation rule without rewriting the stored user data. DOM Studio follows this model through its Forms overview, schema guide, DomForm API, and DomField guide.

1. Define the data contract

Start with semantic data types and validation constraints, not with columns and CSS classes. A clean contract gives the generator enough information to choose sensible defaults while preserving room for layout and component overrides.

Here is a small account form definition:

const accountDefinition = {
  type: 'object',
  properties: {
    name: {
      type: 'string',
      label: 'Full name',
      required: true,
      minLength: 2,
    },
    email: {
      type: 'email',
      label: 'Work email',
      required: true,
    },
    plan: {
      type: 'string',
      label: 'Plan',
      enum: ['starter', 'team', 'enterprise'],
    },
    seats: {
      type: 'integer',
      label: 'Seats',
      minimum: 1,
      maximum: 50,
    },
    updates: {
      type: 'boolean',
      label: 'Send product updates',
    },
  },
};

Expected result: every field has a stable key, a semantic type, and the validation or option data needed for a first usable rendering.

Verification check: save a sample value object separately. It should contain only values, such as { name, email, plan, seats, updates }, with no labels, components, or presentation classes.

Troubleshooting: if a property does not have a clear meaning, do not solve it with a generic text input. Define the correct type or format first. JSON Schema annotations such as titles and descriptions can document the contract and provide useful hints to form generators, but they are not validation rules by themselves.

Watercolour diagram showing schema, component mapping, responsive layout, and validation stages for generated forms

2. Map data types to form components

Next, create a deterministic mapping from semantic types to DOM Studio controls. This gives generated layouts consistency while still allowing specific field overrides.

A practical mapping might look like this:

  • string becomes DomTextInput
  • email becomes DomEmailInput
  • integer or number becomes DomNumberInput
  • boolean becomes DomToggle or DomCheckbox
  • enum becomes DomSelectInput
  • long text becomes DomTextareaInput
  • object becomes a nested DomForm
  • array becomes a repeatable list or JSON list control

For an enum, the generated record can include both the component and options:

const generatedChildren = [
  {
    component: 'DomSelectInput',
    props: {
      name: 'plan',
      label: 'Plan',
      options: [
        { label: 'Starter', value: 'starter' },
        { label: 'Team', value: 'team' },
        { label: 'Enterprise', value: 'enterprise' },
      ],
    },
  },
];

Expected result: the renderer receives normalized children with a component and props, rather than forcing every consuming page to interpret raw schema details.

Verification check: change a field from string to email, regenerate, and confirm that the input component and validation behavior change while the value key stays email.

Troubleshooting: do not infer sensitive business meaning from a field name alone. A field called status needs explicit options and a product-approved label. Generation should establish a strong default, then let a human or configuration override it.

DOM Studio can also generate children from Zod-like shapes and JSON Schema. When you have a different source, such as CMS metadata or an OpenAPI request body, write a small adapter that returns the same child-record format.

3. Add layout records without coupling them to submitted data

A generated form is not finished when it has fields. It needs a layout model that can express sections, grids, grouped controls, help text, and action placement without changing the data contract.

We recommend keeping layout as an adjacent layer. For example, this record places plan and seats in a two-column section on wider screens, while the value model remains flat:

const accountLayout = [
  {
    component: 'section',
    props: { class: 'space-y-4' },
    children: [
      { field: 'name' },
      { field: 'email' },
      {
        component: 'div',
        props: { class: 'grid gap-4 sm:grid-cols-2' },
        children: [
          { field: 'plan' },
          { field: 'seats' },
        ],
      },
      { field: 'updates' },
    ],
  },
];

Your layout resolver can replace each { field: '...' } reference with its generated child record. It can also insert native layout elements or DOM Studio composition components. This is important because layout changes are frequent, while data contracts should be stable.

Expected result: each field is registered once, but can be positioned in a grid, a section, or a grouped control.

Verification check: collapse the viewport to a narrow width. The two-column region should become a readable single-column sequence without changing names, values, or validation paths.

Troubleshooting: avoid placing the same field reference twice. If a field must have both a compact and expanded presentation, control visibility deliberately or create a presentation-only summary, not a second editable field bound to the same path.

Screenshot of getdom.studio

4. Render, validate, and inspect the generated form

Render the normalized children inside DomForm, keep values in v-model, and let the form provider aggregate field state and validation.

<script setup>
import { ref } from 'vue';
import { DomButton, DomForm, jsonSchemaToChildren } from '@getdom/studio/vue';

const values = ref({
  name: '',
  email: '',
  plan: 'team',
  seats: 5,
  updates: true,
});

const children = jsonSchemaToChildren(accountSchema, adapterOptions);

function submit({ values }) {
  // Send validated values to your application boundary.
  console.log(values);
}
</script>

<template>
  <DomForm v-model="values" :children="children" @submit="submit">
    <DomButton type="submit">Save account</DomButton>
  </DomForm>
</template>

Expected result: named children build a value object, report validation errors to the parent form, and preserve nested paths when subforms are used.

Verification check: try submitting an empty required email field, then enter an invalid address. Confirm that the generated field has a descriptive error state and that a valid value clears it.

Troubleshooting: keep runtime server errors in form state, rather than writing them into the authored schema. This preserves the distinction between reusable definition and the state of one submission attempt.

5. Make the generated layout accessible and responsive

Generation does not remove accessibility responsibility. Treat it as a baseline the generator must guarantee.

For every generated field, ensure that the output includes:

  • A visible, programmatically associated label.
  • Clear required indicators that do not rely on color alone.
  • Instructions beside fields with non-obvious formats or constraints.
  • Text descriptions of errors, not only red borders or icons.
  • Logical grouping for related controls, especially radio-style options and multi-part fields.
  • Keyboard-reachable controls, visible focus treatment, and an order that matches the visual flow.

DOM Studio’s field layer can supply label, description, generated ID, error state, and input attributes consistently. We still need to verify custom controls and custom layouts. For example, when a field uses custom visual chrome, pass the label target through to the actual input and preserve error descriptions.

Expected result: a form remains understandable when styles are reduced, errors appear, or a user navigates with a keyboard or assistive technology.

Verification check: tab through the form, trigger two invalid fields, and confirm that each error says what is wrong. Then test the layout at narrow and wide widths to make sure headings, groups, and actions remain in a sensible order.

Troubleshooting: do not hide a label merely because a placeholder looks obvious. Placeholders disappear as people type and do not replace an enduring field label.

6. Test the layout as a product surface

Generated form layouts deserve the same test coverage as hand-built screens. We test the generator, the output, and the task flow.

Start with this compact release checklist:

  1. Schema tests: a type, enum, required rule, default, and nested object map to the expected component records.
  2. Layout tests: all referenced fields exist exactly once, breakpoint rules stack correctly, and sections render in the intended order.
  3. Validation tests: required, format, range, and server-returned errors appear against the correct field path.
  4. Accessibility tests: labels, descriptions, grouped controls, keyboard navigation, and text error feedback work in rendered output.
  5. Task tests: a real user can complete the highest-value workflow with realistic data.

For teams comparing tools, schema-driven form builders such as SurveyJS or VJSF can be useful when a dedicated builder workflow is the priority. We choose DOM Studio when we want an editable Vue and Web Component UI system, source-aware component composition, and generated forms that remain aligned with the application’s own design and code.

Expected result: a new field or layout change is a controlled change to a contract and renderer, not a one-off interface regression.

Verification check: add a company subform and a conditional taxId field in a branch. Confirm the generated paths, validation, mobile sequence, and submitted payload before releasing it.

Troubleshooting: if the generator begins accumulating field-name exceptions, component-specific conditionals, and CSS patches, pause and define a formal adapter or layout rule. Repeated exceptions are a signal that the schema is missing a stable concept.

The completed outcome

You now have a repeatable approach to generated form layouts: define semantic data, normalize it into components, resolve a responsive layout layer, bind it to one form provider, and test the rendered experience as carefully as the schema.

The most useful next action is to choose one existing hand-built form with repeated patterns, model its data contract, and generate only its first section. Compare the generated result with the current implementation, then expand once labels, validation, layout, and mobile behavior are verified.

Build generated forms you can still own

DOM Studio gives us editable primitives, form schemas, field behavior, and layout composition in one Vue-ready system. Use it to create generated form layouts that are consistent by default and still flexible enough for real product work.