Skip to content

Variable: FormWithValidation

ts
const FormWithValidation: DefineComponent<ExtractPropTypes<AppendDefault<{
  additionalMessages: {
     default: () => {
     };
     type: PropType<Record<string, string>>;
  };
  commonFieldOptions: {
     default: () => {
     };
     type: PropType<Record<string, any>>;
  };
  debug: {
     default: boolean;
     type: BooleanConstructor;
  };
  fieldLabels: {
     default: () => {
     };
     type: PropType<Record<string, string>>;
  };
  formInitialValues: {
     required: true;
     type: PropType<Record<string, any>>;
  };
  fullSchema: {
     required: true;
     type: JoiSchemaPropType<any>;
  };
  onPreventedSubmit?: PropType<
     | (...args: [Record<string, any>, ValidationError]) => void
    | undefined>;
  onState:dirty?: PropType<(...args: [boolean]) => void | undefined>;
  onState:errorBag?: PropType<
     | (...args: [Partial<Record<..., ...>>]) => void
    | undefined>;
  onState:errors?: PropType<
     | (...args: [Record<string, ... | ...>]) => void
    | undefined>;
  onState:pending?: PropType<(...args: [boolean]) => void | undefined>;
  onState:submitCount?: PropType<(...args: [number]) => void | undefined>;
  onState:submitting?: PropType<(...args: [boolean]) => void | undefined>;
  onState:touched?: PropType<(...args: [boolean]) => void | undefined>;
  onState:valid?: PropType<(...args: [boolean]) => void | undefined>;
  onState:validating?: PropType<(...args: [boolean]) => void | undefined>;
  onState:values?: PropType<
     | (...args: [Record<string, any>]) => void
    | undefined>;
  options: {
     default: () => {
     };
     type: PropType<AsyncValidationOptions>;
  };
  overrideMessages: {
     default: () => {
     };
     type: PropType<Partial<Record<
        | "alternatives.all"
        | "alternatives.any"
        | "alternatives.match"
        | "alternatives.one"
        | "alternatives.types"
        | "any.custom"
        | "any.default"
        | "any.failover"
        | "any.invalid"
        | "any.only"
        | "any.ref"
        | "any.required"
        | "any.unknown"
        | "array.base"
        | "array.excludes"
        | "array.hasKnown"
        | "array.hasUnknown"
        | "array.includes"
        | "array.includesRequiredBoth"
        | "array.includesRequiredKnowns"
        | "array.includesRequiredUnknowns"
        | "array.length"
        | "array.max"
        | "array.min"
        | "array.orderedLength"
        | "array.sort"
        | "array.sort.mismatching"
        | "array.sort.unsupported"
        | "array.sparse"
        | "array.unique"
        | "boolean.base"
        | "date.base"
        | "date.format"
        | "date.greater"
        | "date.less"
        | "date.max"
        | "date.min"
        | "date.format.iso"
        | "date.format.javascript"
        | "date.format.unix"
        | "function.arity"
        | "function.class"
        | "function.maxArity"
        | "function.minArity"
        | "number.base"
        | "number.greater"
        | "number.infinity"
        | "number.integer"
        | "number.less"
        | "number.max"
        | "number.min"
        | "number.multiple"
        | "number.negative"
        | "number.port"
        | "number.positive"
        | "number.precision"
        | "number.unsafe"
        | "object.and"
        | "object.assert"
        | "object.base"
        | "object.instance"
        | "object.length"
        | "object.max"
        | "object.min"
        | "object.missing"
        | "object.nand"
        | "object.oxor"
        | "object.pattern.match"
        | "object.refType"
        | "object.regex"
        | "object.rename.multiple"
        | "object.rename.override"
        | "object.schema"
        | "object.unknown"
        | "object.with"
        | "object.without"
        | "object.xor"
        | "string.alphanum"
        | "string.base"
        | "string.base64"
        | "string.creditCard"
        | "string.dataUri"
        | "string.domain"
        | "string.email"
        | "string.empty"
        | "string.guid"
        | "string.hex"
        | "string.hexAlign"
        | "string.hostname"
        | "string.ip"
        | "string.ipVersion"
        | "string.isoDate"
        | "string.isoDuration"
        | "string.length"
        | "string.lowercase"
        | "string.max"
        | "string.min"
        | "string.normalize"
        | "string.token"
        | "string.pattern.base"
        | "string.pattern.name"
        | "string.pattern.invert.base"
        | "string.pattern.invert.name"
        | "string.trim"
        | "string.uri"
        | "string.uriCustomScheme"
        | "string.uriRelativeOnly"
        | "string.uppercase"
        | "symbol.base"
        | "symbol.map"
        | "binary.base"
        | "binary.length"
        | "binary.max"
        | "binary.min"
        | "bigint.base"
        | "bigint.greater"
        | "bigint.less"
        | "bigint.max"
        | "bigint.min"
        | "bigint.multiple"
        | "bigint.negative"
        | "bigint.positive"
        | "datetime.base"
        | "datetime.exactly"
        | "datetime.equals"
        | "datetime.after"
        | "datetime.greater"
        | "datetime.before"
        | "datetime.less"
        | "datetime.afterOrEqual"
        | "datetime.min"
        | "datetime.beforeOrEqual"
        | "datetime.max"
        | "datetime.weekend"
        | "datetime.weekday"
        | "phone.base"
        | "phone.invalid"
        | "phone.fixedLine"
        | "phone.mobile"
        | "phone.strictFixedLine"
        | "phone.strictMobile"
        | "phone.fixedLineOrMobile"
        | "phone.tollFree"
        | "phone.premiumRate"
        | "phone.sharedCost"
        | "phone.voip"
        | "phone.personalNumber"
        | "phone.pager"
        | "phone.uan"
        | "phone.voicemail"
        | "phone.unknown"
       | "phone.types", string>>>;
  };
  specificFieldOptions: {
     default: () => {
     };
     type: PropType<Record<string, Record<string, any>>>;
  };
  submissionHandler: {
     required: true;
     type: PropType<(values: any) => MaybePromise<void>>;
  };
}, {
}>>, {
  formErrorBag: Ref<Partial<Record<string, string[]>>, Partial<Record<string, string[]>>>;
  formErrors: ComputedRef<Partial<Record<string, string | undefined>>>;
  formIsDirty: ComputedRef<boolean>;
  formIsPending: ComputedRef<boolean>;
  formIsSubmitting: Ref<boolean, boolean>;
  formIsTouched: ComputedRef<boolean>;
  formIsValid: ComputedRef<boolean>;
  formIsValidating: Ref<boolean, boolean>;
  formSubmitCount: Ref<number, number>;
  formValues: any;
  reset: () => void;
  setFieldTouched: (field: string, isTouched: boolean) => void;
  setFieldValue: (field: string, value: any) => void;
  setTouched: (fields:
     | boolean
    | Partial<Record<string, boolean>>) => void;
  setValues: (fields: any, shouldValidate?: boolean) => void;
  submit: () => void;
  validate: (opts?: Partial<ValidationOptions$1>) => Promise<FormValidationResult<any, any>>;
  validateField: <TPath>(field: TPath, opts?: Partial<ValidationOptions$1>) => Promise<ValidationResult<any>>;
}, {
}, {
}, {
}, ComponentOptionsMixin, ComponentOptionsMixin, EmitFunctions<{
  preventedSubmit: (values: Record<string, any>, error: ValidationError) => boolean;
  state:dirty: (is: boolean) => boolean;
  state:errorBag: (errors: Partial<Record<string, string[]>>) => boolean;
  state:errors: (errors: Record<string, string | undefined>) => boolean;
  state:pending: (is: boolean) => boolean;
  state:submitCount: (count: number) => boolean;
  state:submitting: (is: boolean) => boolean;
  state:touched: (is: boolean) => boolean;
  state:valid: (is: boolean) => boolean;
  state:validating: (is: boolean) => boolean;
  state:values: (values: Record<string, any>) => values is { [key: string]: unknown };
}>, string, PublicProps, ToResolvedProps<ExtractPropTypes<AppendDefault<{
  additionalMessages: {
     default: () => {
     };
     type: PropType<Record<string, string>>;
  };
  commonFieldOptions: {
     default: () => {
     };
     type: PropType<Record<string, any>>;
  };
  debug: {
     default: boolean;
     type: BooleanConstructor;
  };
  fieldLabels: {
     default: () => {
     };
     type: PropType<Record<string, string>>;
  };
  formInitialValues: {
     required: true;
     type: PropType<Record<string, any>>;
  };
  fullSchema: {
     required: true;
     type: JoiSchemaPropType<any>;
  };
  onPreventedSubmit?: PropType<
     | (...args: [Record<..., ...>, ValidationError]) => void
    | undefined>;
  onState:dirty?: PropType<(...args: [boolean]) => void | undefined>;
  onState:errorBag?: PropType<
     | (...args: [Partial<...>]) => void
    | undefined>;
  onState:errors?: PropType<
     | (...args: [Record<..., ...>]) => void
    | undefined>;
  onState:pending?: PropType<(...args: [boolean]) => void | undefined>;
  onState:submitCount?: PropType<(...args: [number]) => void | undefined>;
  onState:submitting?: PropType<(...args: [boolean]) => void | undefined>;
  onState:touched?: PropType<(...args: [boolean]) => void | undefined>;
  onState:valid?: PropType<(...args: [boolean]) => void | undefined>;
  onState:validating?: PropType<(...args: [boolean]) => void | undefined>;
  onState:values?: PropType<
     | (...args: [Record<..., ...>]) => void
    | undefined>;
  options: {
     default: () => {
     };
     type: PropType<AsyncValidationOptions>;
  };
  overrideMessages: {
     default: () => {
     };
     type: PropType<Partial<Record<
        | "alternatives.all"
        | "alternatives.any"
        | "alternatives.match"
        | "alternatives.one"
        | "alternatives.types"
        | "any.custom"
        | "any.default"
        | "any.failover"
        | "any.invalid"
        | "any.only"
        | "any.ref"
        | "any.required"
        | "any.unknown"
        | "array.base"
        | "array.excludes"
        | "array.hasKnown"
        | "array.hasUnknown"
        | "array.includes"
        | "array.includesRequiredBoth"
        | "array.includesRequiredKnowns"
        | "array.includesRequiredUnknowns"
        | "array.length"
        | "array.max"
        | "array.min"
        | "array.orderedLength"
        | "array.sort"
        | "array.sort.mismatching"
        | "array.sort.unsupported"
        | "array.sparse"
        | "array.unique"
        | "boolean.base"
        | "date.base"
        | "date.format"
        | "date.greater"
        | "date.less"
        | "date.max"
        | "date.min"
        | "date.format.iso"
        | "date.format.javascript"
        | "date.format.unix"
        | "function.arity"
        | "function.class"
        | "function.maxArity"
        | "function.minArity"
        | "number.base"
        | "number.greater"
        | "number.infinity"
        | "number.integer"
        | "number.less"
        | "number.max"
        | "number.min"
        | "number.multiple"
        | "number.negative"
        | "number.port"
        | "number.positive"
        | "number.precision"
        | "number.unsafe"
        | "object.and"
        | "object.assert"
        | "object.base"
        | "object.instance"
        | "object.length"
        | "object.max"
        | "object.min"
        | "object.missing"
        | "object.nand"
        | "object.oxor"
        | "object.pattern.match"
        | "object.refType"
        | "object.regex"
        | "object.rename.multiple"
        | "object.rename.override"
        | "object.schema"
        | "object.unknown"
        | "object.with"
        | "object.without"
        | "object.xor"
        | "string.alphanum"
        | "string.base"
        | "string.base64"
        | "string.creditCard"
        | "string.dataUri"
        | "string.domain"
        | "string.email"
        | "string.empty"
        | "string.guid"
        | "string.hex"
        | "string.hexAlign"
        | "string.hostname"
        | "string.ip"
        | "string.ipVersion"
        | "string.isoDate"
        | "string.isoDuration"
        | "string.length"
        | "string.lowercase"
        | "string.max"
        | "string.min"
        | "string.normalize"
        | "string.token"
        | "string.pattern.base"
        | "string.pattern.name"
        | "string.pattern.invert.base"
        | "string.pattern.invert.name"
        | "string.trim"
        | "string.uri"
        | "string.uriCustomScheme"
        | "string.uriRelativeOnly"
        | "string.uppercase"
        | "symbol.base"
        | "symbol.map"
        | "binary.base"
        | "binary.length"
        | "binary.max"
        | "binary.min"
        | "bigint.base"
        | "bigint.greater"
        | "bigint.less"
        | "bigint.max"
        | "bigint.min"
        | "bigint.multiple"
        | "bigint.negative"
        | "bigint.positive"
        | "datetime.base"
        | "datetime.exactly"
        | "datetime.equals"
        | "datetime.after"
        | "datetime.greater"
        | "datetime.before"
        | "datetime.less"
        | "datetime.afterOrEqual"
        | "datetime.min"
        | "datetime.beforeOrEqual"
        | "datetime.max"
        | "datetime.weekend"
        | "datetime.weekday"
        | "phone.base"
        | "phone.invalid"
        | "phone.fixedLine"
        | "phone.mobile"
        | "phone.strictFixedLine"
        | "phone.strictMobile"
        | "phone.fixedLineOrMobile"
        | "phone.tollFree"
        | "phone.premiumRate"
        | "phone.sharedCost"
        | "phone.voip"
        | "phone.personalNumber"
        | "phone.pager"
        | "phone.uan"
        | "phone.voicemail"
        | "phone.unknown"
       | "phone.types", string>>>;
  };
  specificFieldOptions: {
     default: () => {
     };
     type: PropType<Record<string, Record<string, any>>>;
  };
  submissionHandler: {
     required: true;
     type: PropType<(values: any) => MaybePromise<void>>;
  };
}, {
}>>, EmitFunctions<{
  preventedSubmit: (values: Record<string, any>, error: ValidationError) => boolean;
  state:dirty: (is: boolean) => boolean;
  state:errorBag: (errors: Partial<Record<string, string[]>>) => boolean;
  state:errors: (errors: Record<string, string | undefined>) => boolean;
  state:pending: (is: boolean) => boolean;
  state:submitCount: (count: number) => boolean;
  state:submitting: (is: boolean) => boolean;
  state:touched: (is: boolean) => boolean;
  state:valid: (is: boolean) => boolean;
  state:validating: (is: boolean) => boolean;
  state:values: (values: Record<string, any>) => values is { [key: string]: unknown };
}>>, {
  additionalMessages: Record<string, string>;
  commonFieldOptions: Record<string, any>;
  debug: boolean;
  fieldLabels: Record<string, string>;
  options: AsyncValidationOptions;
  overrideMessages: Partial<Record<
     | "alternatives.all"
     | "alternatives.any"
     | "alternatives.match"
     | "alternatives.one"
     | "alternatives.types"
     | "any.custom"
     | "any.default"
     | "any.failover"
     | "any.invalid"
     | "any.only"
     | "any.ref"
     | "any.required"
     | "any.unknown"
     | "array.base"
     | "array.excludes"
     | "array.hasKnown"
     | "array.hasUnknown"
     | "array.includes"
     | "array.includesRequiredBoth"
     | "array.includesRequiredKnowns"
     | "array.includesRequiredUnknowns"
     | "array.length"
     | "array.max"
     | "array.min"
     | "array.orderedLength"
     | "array.sort"
     | "array.sort.mismatching"
     | "array.sort.unsupported"
     | "array.sparse"
     | "array.unique"
     | "boolean.base"
     | "date.base"
     | "date.format"
     | "date.greater"
     | "date.less"
     | "date.max"
     | "date.min"
     | "date.format.iso"
     | "date.format.javascript"
     | "date.format.unix"
     | "function.arity"
     | "function.class"
     | "function.maxArity"
     | "function.minArity"
     | "number.base"
     | "number.greater"
     | "number.infinity"
     | "number.integer"
     | "number.less"
     | "number.max"
     | "number.min"
     | "number.multiple"
     | "number.negative"
     | "number.port"
     | "number.positive"
     | "number.precision"
     | "number.unsafe"
     | "object.and"
     | "object.assert"
     | "object.base"
     | "object.instance"
     | "object.length"
     | "object.max"
     | "object.min"
     | "object.missing"
     | "object.nand"
     | "object.oxor"
     | "object.pattern.match"
     | "object.refType"
     | "object.regex"
     | "object.rename.multiple"
     | "object.rename.override"
     | "object.schema"
     | "object.unknown"
     | "object.with"
     | "object.without"
     | "object.xor"
     | "string.alphanum"
     | "string.base"
     | "string.base64"
     | "string.creditCard"
     | "string.dataUri"
     | "string.domain"
     | "string.email"
     | "string.empty"
     | "string.guid"
     | "string.hex"
     | "string.hexAlign"
     | "string.hostname"
     | "string.ip"
     | "string.ipVersion"
     | "string.isoDate"
     | "string.isoDuration"
     | "string.length"
     | "string.lowercase"
     | "string.max"
     | "string.min"
     | "string.normalize"
     | "string.token"
     | "string.pattern.base"
     | "string.pattern.name"
     | "string.pattern.invert.base"
     | "string.pattern.invert.name"
     | "string.trim"
     | "string.uri"
     | "string.uriCustomScheme"
     | "string.uriRelativeOnly"
     | "string.uppercase"
     | "symbol.base"
     | "symbol.map"
     | "binary.base"
     | "binary.length"
     | "binary.max"
     | "binary.min"
     | "bigint.base"
     | "bigint.greater"
     | "bigint.less"
     | "bigint.max"
     | "bigint.min"
     | "bigint.multiple"
     | "bigint.negative"
     | "bigint.positive"
     | "datetime.base"
     | "datetime.exactly"
     | "datetime.equals"
     | "datetime.after"
     | "datetime.greater"
     | "datetime.before"
     | "datetime.less"
     | "datetime.afterOrEqual"
     | "datetime.min"
     | "datetime.beforeOrEqual"
     | "datetime.max"
     | "datetime.weekend"
     | "datetime.weekday"
     | "phone.base"
     | "phone.invalid"
     | "phone.fixedLine"
     | "phone.mobile"
     | "phone.strictFixedLine"
     | "phone.strictMobile"
     | "phone.fixedLineOrMobile"
     | "phone.tollFree"
     | "phone.premiumRate"
     | "phone.sharedCost"
     | "phone.voip"
     | "phone.personalNumber"
     | "phone.pager"
     | "phone.uan"
     | "phone.voicemail"
     | "phone.unknown"
    | "phone.types", string>>;
  specificFieldOptions: Record<string, Record<string, any>>;
}, FormWithValidationSlots, {
}, {
}, string, ComponentProvideOptions, true, {
}, any>;

Enterprise-grade form validation component that provides a complete form wrapper with validation state management, field binding generation, and event emission.

This component wraps the useValidation composable in a reusable component interface, providing automatic form element generation, state emission to parent components, and scoped display utilities for responsive form layouts.

Example

vue
<template>
  <FormWithValidation
    :full-schema="userSchema"
    :form-initial-values="{ name: '', email: '' }"
    :submission-handler="handleSubmit"
    @state:valid="onValidationChange"
  >
    <template #default="{ formFieldBindings, useField, formIsValid }">
      <VTextField v-bind="formFieldBindings.name" label="Name" />
      <VTextField v-bind="formFieldBindings.email" label="Email" />

      <!-- Nested field example -->
      <VTextField v-bind="useField('profile.bio')" label="Bio" />

      <VBtn :disabled="!formIsValid" type="submit"> Submit </VBtn>
    </template>
  </FormWithValidation>
</template>