Skip to content

Vuetify ​

Map Vuetify inputs to Formhaus field types through the components prop of FormRenderer from @formhaus/vue.

Open in StackBlitz · Source

Install ​

bash
npm install @formhaus/core @formhaus/vue vuetify

Component map ​

ts
import type { FieldComponentMap } from '@formhaus/vue';
import AutocompleteField from './fields/AutocompleteField.vue';
import CheckboxField from './fields/CheckboxField.vue';
import FileField from './fields/FileField.vue';
import RadioField from './fields/RadioField.vue';
import SelectField from './fields/SelectField.vue';
import SwitchField from './fields/SwitchField.vue';
import TextField from './fields/TextField.vue';
import TextareaField from './fields/TextareaField.vue';

export const components: Partial<FieldComponentMap> = {
  text: TextField,
  email: TextField,
  phone: TextField,
  number: TextField,
  password: TextField,
  date: TextField,
  datetime: TextField,
  select: SelectField,
  autocomplete: AutocompleteField,
  multiselect: SelectField,
  checkbox: CheckboxField,
  radio: RadioField,
  switch: SwitchField,
  file: FileField,
  textarea: TextareaField,
};

Text field ​

vue
<script setup>
const props = defineProps({
  field: { type: Object, required: true },
  value: { default: undefined },
  error: { type: String, default: undefined },
  loading: { type: Boolean, default: false },
  disabled: { type: Boolean, default: false },
});

const emit = defineEmits(['update:value', 'blur', 'focus']);

const inputType =
  props.field.type === 'email' ? 'email'
  : props.field.type === 'password' ? 'password'
  : props.field.type === 'number' ? 'number'
  : props.field.type === 'date' ? 'date'
  : props.field.type === 'datetime' ? 'datetime-local'
  : props.field.type === 'phone' ? 'tel'
  : 'text';
</script>

<template>
  <v-text-field
    :id="field.key"
    :label="field.label"
    :type="inputType"
    :model-value="value != null ? String(value) : ''"
    :placeholder="field.placeholder"
    :error-messages="error ? [error] : []"
    :hint="field.helperText"
    :persistent-hint="!!field.helperText"
    :disabled="disabled || loading"
    @update:model-value="(v) => emit('update:value', field.type === 'number' ? Number(v) : v)"
    @blur="emit('blur')"
    @focus="emit('focus')"
  />
</template>

App ​

vue
<script setup>
import { FormRenderer } from '@formhaus/vue';
import { components } from './component-map';
import FormActions from './actions/FormActions.vue';
import StepProgress from './actions/StepProgress.vue';
import definition from './definition.json';

function onSubmit(values) {
  console.log('Submitted:', values);
}
</script>

<template>
  <v-app>
    <v-container style="max-width: 600px">
      <FormRenderer
        :definition="definition"
        :components="components"
        :actions-component="FormActions"
        :progress-component="StepProgress"
        @submit="onSubmit"
      />
    </v-container>
  </v-app>
</template>

The other renderers are in src/fields and src/actions.

Server re-validation ​

The example validates in the browser only. To check the same rules on the server, build a FormEngine from the same definition and call validate(), then pass the returned errors to the errors prop. See Nuxt for a complete server route.