Composables API
QuickForms provides Vue 3 composables for building custom components and accessing form state.
useFormField
Hook for managing individual field state with automatic validation and label handling.
Signature
function useFormField(
path: string,
schema: JSONSchema,
options?: { label?: string }
): UseFormFieldReturnParameters
path- Field path in form data (e.g.,"email","user.address.city")schema- JSON Schema definition for this fieldoptions- Optional configurationlabel- Override the field label (defaults toschema.titleorpath)
Return Value
interface UseFormFieldReturn {
value: Ref<any> // Reactive field value (v-model compatible)
errorMessage: ComputedRef<string | null> // Current validation error
errors: Ref<string[]> // All validation errors
setValue: (val: any) => void // Programmatically set value
setTouched: (touched: boolean) => void // Mark field as touched
meta: FieldMeta // VeeValidate field metadata
label: ComputedRef<string> // Display label
hint: ComputedRef<string | undefined> // Hint text
hintMode: ComputedRef<'always' | 'focus' | 'hover'> // When to show hint
required: ComputedRef<boolean> // Whether field is required
}Example Usage
<script setup lang="ts">
import { useFormField } from '@quickflo/quickforms-vue'
import type { JSONSchema } from '@quickflo/quickforms'
const props = defineProps<{
schema: JSONSchema
path: string
disabled?: boolean
}>()
const { value, errorMessage, label, hint, required } = useFormField(
props.path,
props.schema
)
</script>
<template>
<div class="field">
<label>
{{ label }}
<span v-if="required" class="required">*</span>
</label>
<input
v-model="value"
:disabled="disabled"
:aria-invalid="!!errorMessage"
/>
<div v-if="hint" class="hint">{{ hint }}</div>
<div v-if="errorMessage" class="error">{{ errorMessage }}</div>
</div>
</template>Features
Automatic Validation:
- JSON Schema validation (type, format, min/max, pattern, etc.)
- Custom validators from form options
- Async validator support with debouncing
- Custom error messages from
x-error-messagesor form options
Smart Error Display:
- Respects
validationModefrom form options ValidateAndShow- Shows errors as you typeValidateAndHide- Validates silently (returnsnullfor errorMessage)NoValidation- Skips all validation
Hint Management:
- Reads from
x-hintordescription - Supports HTML in
x-hint - Applies
hintRendererif provided in form options - Respects
x-hint-modeor globalcomponentDefaults.hints.showMode
Label Resolution:
- Uses override from
options.labelif provided - Falls back to
schema.title - Falls back to
path
Advanced: Custom Validators
The composable automatically runs custom validators from form options:
const options = {
validators: {
email: async (value, allValues, context) => {
const response = await fetch(`/guide/check-email?email=${value}`)
const { available } = await response.json()
return available || 'Email already taken'
}
},
validatorDebounce: {
email: 500 // Debounce async validation by 500ms
}
}Advanced: Programmatic Control
<script setup lang="ts">
const { value, setValue, setTouched, meta } = useFormField(path, schema)
// Set value programmatically
const resetField = () => {
setValue('')
setTouched(false)
}
// Check field state
console.log(meta.value.dirty) // Has value changed?
console.log(meta.value.touched) // Has field been focused?
console.log(meta.value.valid) // Is field valid?
</script>useFormContext
Access form-level context and configuration.
Signature
function useFormContext(): FormContext | undefinedReturn Value
interface FormContext {
schema: JSONSchema // Root schema
validationMode: ValidationMode // Current validation mode
readonly?: boolean // Form-level readonly
disabled?: boolean // Form-level disabled
errorMessages?: ErrorMessages // Custom error messages
validators?: ValidatorMap // Custom validators
validatorDebounce?: number | Record<string, number>
hintRenderer?: HintRenderer // Custom hint renderer
componentDefaults?: ComponentDefaults
context?: Record<string, any> // User-provided context
formValues?: () => any // Get all form values
}Example Usage
<script setup lang="ts">
import { useFormContext } from '@quickflo/quickforms-vue'
const formContext = useFormContext()
// Check form-level state
const isReadonly = computed(() => formContext?.readonly || false)
const isDisabled = computed(() => formContext?.disabled || false)
// Access user context
const userId = computed(() => formContext?.context?.userId)
// Get all form values
const allValues = computed(() => formContext?.formValues?.() || {})
</script>Use Cases
1. Custom Components:
Access form configuration in custom field components:
<script setup lang="ts">
import { useFormContext } from '@quickflo/quickforms-vue'
const context = useFormContext()
// Apply global component defaults
const defaults = context?.componentDefaults?.input || {}
</script>2. Cross-Field Logic:
Access other field values for dependent validation:
<script setup lang="ts">
const context = useFormContext()
const validatePasswordConfirm = (value: string) => {
const allValues = context?.formValues?.() || {}
return value === allValues.password || 'Passwords must match'
}
</script>3. Role-Based UI:
Show/hide elements based on user context:
<script setup lang="ts">
const context = useFormContext()
const isAdmin = computed(() => context?.context?.role === 'admin')
</script>
<template>
<div v-if="isAdmin">
<!-- Admin-only content -->
</div>
</template>provideFormContext
Provide form context to child components (used internally by DynamicForm).
Signature
function provideFormContext(context: FormContext): voidUsage
This is primarily used internally by the DynamicForm component. You typically won't need to call this directly unless building a custom form wrapper.
import { provideFormContext } from '@quickflo/quickforms-vue'
// In a custom form wrapper component
provideFormContext({
schema: mySchema,
validationMode: 'ValidateAndShow',
readonly: false,
// ... other context
})Utility Functions
getHint
Extract hint text from schema (used internally by useFormField).
function getHint(schema: JSONSchema): string | undefinedReturns x-hint if present, otherwise description.
Example
import { getHint } from '@quickflo/quickforms-vue'
const hint = getHint({
type: 'string',
description: 'Plain text hint',
'x-hint': 'HTML hint with <a>link</a>'
})
console.log(hint) // "HTML hint with <a>link</a>"Type Definitions
ValidationMode
type ValidationMode = 'ValidateAndShow' | 'ValidateAndHide' | 'NoValidation'FieldMeta
From VeeValidate:
interface FieldMeta {
touched: boolean // Has field been focused?
dirty: boolean // Has value changed from initial?
valid: boolean // Is field valid?
pending: boolean // Is async validation running?
initialValue: any // Original value
}HintRenderer
Custom function to transform hint text:
type HintRenderer = (
hint: string,
context: {
schema: JSONSchema
path: string
value: any
}
) => stringValidatorMap
Custom validators keyed by field path:
type ValidatorMap = Record<string, ValidatorFunction>
type ValidatorFunction = (
value: any,
allValues: Record<string, any>,
context: Record<string, any>
) => boolean | string | Promise<boolean | string> | ValidationResult
interface ValidationResult {
valid: boolean
message?: string
}Next Steps
- Custom Components - Build custom fields using these composables
- Custom Validators - Add custom validation logic
- Form Options - Configure form-level behavior