Skip to content

Import and export a form

FormBuilder provides an official import/export interface in the toolbar.

Since 0.1.13, two export formats are available:

  • Complete document: recommended versioned format containing schema, values, settings, and theme;
  • Schema only: historical array format compatible with existing integrations.

Complete document export

The Export button opens a dialog containing the canonical JSON document. Users can:

  • copy it to the clipboard;
  • download a .qform.json file named from the form.

document-export is emitted after copying, downloading, or calling the public API:

vue
<FormBuilder
  builder-id="forms-admin"
  @document-export="payload => auditExport(payload.document)"
/>
ts
const builder = ref<FormBuilderPublicApi | null>(null)
const document = builder.value?.exportDocument({
  metadata: { source: 'admin-ui' },
})

A complete document may contain entered values, including personal data. Review or anonymize values before sharing the file. File, Blob, and FileList objects are not serializable: upload files separately and store only a validated reference.

The format exposes documentVersion, schemaVersion, and themeVersion. See Versioning and migrations.

Historical schema export

The Schema only mode and exportSchema() API remain compatible:

ts
const schema = builder.value?.exportSchema() || []

The schema-export event is unchanged.

Import

The Import button accepts:

  • a versioned QForm Builder document;
  • a historical { schema, values, settings, savedAt } state;
  • a node array;
  • a { "schema": [...] } envelope;
  • pasted JSON or a .json / .qform.json file.

A valid import migrates and sanitizes the content before applying it.

vue
<FormBuilder
  builder-id="forms-admin"
  @document-import="payload => auditMigration(payload)"
  @schema-import="schema => auditSchema(schema)"
  @error="handleBuilderError"
/>

For a schema-only source, current values and settings are preserved. For a complete document, they are applied in the same transaction.

ts
builder.value?.importDocument(payload, {
  applyValues: true,
  applySettings: true,
})

importSchema() remains available to explicitly replace only the schema.

Validation and security

The same validation is applied by the dialog, importDocument(), and public helpers:

  • 2 MB size limit;
  • maximum depth and value count;
  • non-serializable objects and non-finite numbers rejected;
  • prototype-pollution keys rejected;
  • on* event attributes rejected;
  • $cmp, script, iframe, object, embed, style, link, meta, base, and template rejected;
  • javascript:, vbscript:, and data: URLs rejected;
  • CSS expressions and unsafe URLs rejected;
  • noopener noreferrer added to target="_blank" links;
  • unknown future versions explicitly rejected;
  • theme, sizes, metadata, and icons normalized.

Public helpers:

ts
import {
  parseQFormBuilderDocument,
  migrateQFormBuilderDocument,
} from '@vevedh/qform-builder-layer/migrations'

import {
  parseQFormBuilderSchema,
  sanitizeQFormBuilderSchema,
} from '@vevedh/qform-builder-layer/schema-transfer'

Server rule

Browser validation is not a security boundary. The backend must:

  1. enforce authentication and write permissions;
  2. limit payload size;
  3. validate schema, values, and settings again;
  4. reject unsupported future versions;
  5. protect system fields (ownerId, tenantId, dates, and version) in service hooks;
  6. enforce optimistic concurrency control;
  7. audit sensitive imports, migrations, and updates.

QForm Builder — Nuxt 4, Quasar and FormKit layer for dynamic forms.