Skip to content

Latest commit

 

History

History
629 lines (476 loc) · 10.6 KB

File metadata and controls

629 lines (476 loc) · 10.6 KB

Components API

QuickForms provides pre-built components for all standard JSON Schema types.

DynamicForm

Main form component that generates fields from JSON Schema.

Props

interface DynamicFormProps {
  schema: JSONSchema            // JSON Schema definition
  modelValue: any               // Form data (v-model)
  options?: FormOptions         // Form configuration
}

Events

interface DynamicFormEmits {
  'update:modelValue': (value: any) => void     // Form data changed
  'validation': (result: ValidationResult) => void  // Validation state changed
}

interface ValidationResult {
  valid: boolean
  errors: Record<string, string>
}

Example

<script setup lang="ts">
import { ref } from 'vue'
import { DynamicForm } from '@quickflo/quickforms-vue'
import type { JSONSchema } from '@quickflo/quickforms'

const schema: JSONSchema = {
  type: 'object',
  properties: {
    name: { type: 'string', title: 'Name' },
    email: { type: 'string', format: 'email', title: 'Email' }
  },
  required: ['name', 'email']
}

const formData = ref({})

const handleValidation = (result: ValidationResult) => {
  console.log('Valid:', result.valid)
  console.log('Errors:', result.errors)
}
</script>

<template>
  <DynamicForm
    :schema="schema"
    v-model="formData"
    :options="{ validationMode: 'ValidateAndShow' }"
    @validation="handleValidation"
  />
</template>

Slots

None. The DynamicForm component automatically renders fields based on the schema. For customization, use the component registry.


FieldRenderer

Internal component that selects and renders the appropriate field component based on schema.

Props

interface FieldRendererProps {
  schema: JSONSchema
  path: string
}

Usage

Used internally by DynamicForm and container fields (ObjectField, ArrayField, OneOfField). You typically won't use this directly unless building a custom layout component.

<template>
  <FieldRenderer :schema="fieldSchema" :path="fieldPath" />
</template>

Field Components

Pre-built components for each field type. All field components share the same props interface:

Common Props

interface FieldProps {
  schema: JSONSchema    // Field's JSON Schema
  path: string          // Field path in form data
  disabled?: boolean    // Disable field input
  readonly?: boolean    // Make field read-only
}

StringField

Renders text inputs for string fields.

Handles

  • type: 'string'
  • Various formats: email, url, password, textarea

Example Schema

{
  type: 'string',
  title: 'Full Name',
  minLength: 2,
  maxLength: 100
}

Format variants:

// Email
{ type: 'string', format: 'email' }

// URL
{ type: 'string', format: 'url' }

// Password
{ type: 'string', format: 'password' }

// Textarea
{ type: 'string', format: 'textarea' }

NumberField

Renders number inputs.

Handles

  • type: 'number'
  • type: 'integer'

Example Schema

{
  type: 'number',
  title: 'Age',
  minimum: 0,
  maximum: 120
}
{
  type: 'integer',
  title: 'Quantity',
  multipleOf: 5
}

BooleanField

Renders checkboxes for boolean values.

Handles

  • type: 'boolean'

Example Schema

{
  type: 'boolean',
  title: 'Accept Terms',
  default: false
}

EnumField

Renders select dropdowns for enum values.

Handles

  • Fields with enum property

Example Schema

{
  type: 'string',
  title: 'Country',
  enum: ['US', 'CA', 'UK', 'DE'],
  'x-enum-labels': {
    US: 'United States',
    CA: 'Canada',
    UK: 'United Kingdom',
    DE: 'Germany'
  }
}

Multiple selection:

{
  type: 'array',
  title: 'Tags',
  items: {
    type: 'string',
    enum: ['javascript', 'typescript', 'vue', 'react']
  },
  uniqueItems: true
}

DateField

Renders date/time pickers.

Handles

  • format: 'date'
  • format: 'time'
  • format: 'date-time'

Example Schema

// Date
{
  type: 'string',
  format: 'date',
  title: 'Birth Date'
}

// Time
{
  type: 'string',
  format: 'time',
  title: 'Appointment Time'
}

// DateTime
{
  type: 'string',
  format: 'date-time',
  title: 'Event Start'
}

ObjectField

Renders nested object fields.

Handles

  • type: 'object'

Example Schema

{
  type: 'object',
  title: 'Address',
  properties: {
    street: { type: 'string', title: 'Street' },
    city: { type: 'string', title: 'City' },
    zip: { type: 'string', title: 'ZIP Code' }
  },
  required: ['street', 'city']
}

Rendering:

  • Plain Vue: Simple wrapper with nested fields
  • Quasar: Expandable card with QExpansionItem

JsonField

Renders a JSON editor for freeform object configuration.

Handles

  • type: 'object' with additionalProperties but no defined properties
  • Any field with x-render: 'jsoneditor'

Example Schema

Auto-detected (freeform object):

{
  type: 'object',
  title: 'Custom Configuration',
  description: 'Freeform JSON object',
  additionalProperties: {}
}

Explicit via x-render:

{
  type: 'object',
  title: 'API Settings',
  description: 'Configuration in JSON format',
  'x-render': 'jsoneditor',
  'x-rows': 10  // Control textarea height
}

With custom props (Quasar):

{
  type: 'object',
  title: 'Metadata',
  'x-render': 'jsoneditor',
  'x-rows': 8,
  'x-quasar-props': {
    dense: false,
    color: 'secondary'
  },
  'x-quickforms-quasar': {
    prependIcon: 'settings',
    iconColor: 'primary',
    showFormatHint: false  // Hide info icon
  }
}

Hide format hint (Vue):

{
  type: 'object',
  'x-render': 'jsoneditor',
  'x-show-format-hint': false  // Hide info icon
}

Features

  • Tab indentation: Press Tab to insert 2 spaces
  • Format shortcut: Press Ctrl+Space to auto-format JSON
  • Real-time validation: Shows parse errors as you type
  • Monospace font: Better readability for JSON
  • Info icon: Hover tooltip showing format shortcut (can be hidden)
  • No auto-formatting: Only formats on initial load or manual trigger

Keyboard Shortcuts

  • Ctrl+Space: Format JSON with proper indentation
  • Tab: Insert 2 spaces for indentation
  • Enter: Insert new line (does not submit form)

Configuration

Global defaults (Quasar):

const formOptions = {
  componentDefaults: {
    jsoneditor: {
      dense: true,
      color: 'primary',
      rows: 12
    }
  },
  quickformsDefaults: {
    jsoneditor: {
      prependIcon: 'code',
      iconColor: 'grey-7',
      showFormatHint: true  // Default: true
    }
  }
}

ArrayField

Renders dynamic array fields with add/remove buttons.

Handles

  • type: 'array'

Example Schema

// Simple array
{
  type: 'array',
  title: 'Tags',
  items: { type: 'string' }
}

// Array of objects
{
  type: 'array',
  title: 'Contacts',
  items: {
    type: 'object',
    properties: {
      name: { type: 'string', title: 'Name' },
      phone: { type: 'string', title: 'Phone' }
    }
  },
  minItems: 1,
  maxItems: 5
}

Features:

  • Add/remove buttons
  • Respects minItems and maxItems
  • Drag-to-reorder (if enabled)

OneOfField

Renders conditional schemas with a selector.

Handles

  • Schemas with oneOf

Example Schema

{
  oneOf: [
    {
      type: 'object',
      title: 'Individual',
      properties: {
        name: { type: 'string', title: 'Full Name' },
        ssn: { type: 'string', title: 'SSN' }
      }
    },
    {
      type: 'object',
      title: 'Business',
      properties: {
        company: { type: 'string', title: 'Company Name' },
        ein: { type: 'string', title: 'EIN' }
      }
    }
  ]
}

Rendering:

  • Dropdown to select which schema to use
  • Dynamically renders fields based on selection

AllOfField

Renders merged schemas (intersection).

Handles

  • Schemas with allOf

Example Schema

{
  allOf: [
    {
      type: 'object',
      properties: {
        name: { type: 'string', title: 'Name' }
      }
    },
    {
      type: 'object',
      properties: {
        email: { type: 'string', format: 'email', title: 'Email' }
      }
    }
  ]
}

Behavior:

  • Merges all schemas in allOf array
  • Renders as a single flat object

HiddenField

Renders a hidden input (no visual output).

Handles

  • Fields with 'x-hidden': true

Example Schema

{
  type: 'string',
  'x-hidden': true,
  default: 'hidden-value'
}

Use Cases:

  • Hidden form fields
  • Tracking fields
  • Server-side data

Customizing Built-in Components

You cannot modify built-in components directly, but you can:

1. Override with Custom Component

Register a custom component with higher priority:

import { createDefaultRegistry, rankWith, isStringType } from '@quickflo/quickforms-vue'
import CustomStringField from './CustomStringField.vue'

const registry = createDefaultRegistry()

// Override default StringField (priority 2) with priority 20
registry.register('custom-string', CustomStringField, rankWith(20, isStringType))

2. Use Component Defaults (Quasar)

Configure global defaults for all components:

import { createQuasarRegistry } from '@quickflo/quickforms-quasar'

const options = {
  registry: createQuasarRegistry(),
  componentDefaults: {
    global: {
      outlined: true,
      dense: true
    },
    input: {
      clearable: true
    }
  }
}

3. Per-Field Overrides

Use schema extensions:

{
  type: 'string',
  title: 'Email',
  'x-component-props': {
    placeholder: 'you@example.com',
    autocomplete: 'email'
  }
}

Component Props Reference

All field components receive these props automatically:

Prop Type Description
schema JSONSchema Field's JSON Schema definition
path string Field path (e.g., "email", "user.name")
disabled boolean Form-level disabled state
readonly boolean Form-level readonly state

Field components use useFormField(path, schema) to access:

  • value - Reactive field value
  • errorMessage - Validation error
  • label - Display label
  • hint - Hint text
  • required - Required status

See Composables API for details.


Next Steps