Cookbook: register page

A complete sign-up form: cross-field validation, a must-accept checkbox, and a dialog awaited before the form resets.

Register

examples/cookbook/Register.vue
<template>
  <Form
    class="mx-auto max-w-md"
    @submit="onSubmit"
  >
    <FormFields :options="fields" />

    <Button
      type="submit"
      class="mt-6"
      block
    >
      Register
    </Button>
  </Form>
</template>

<script lang="ts" setup>
const schema = v.pipe(
  v.object({
    username: v.pipe(v.string(), v.nonEmpty(), v.minLength(3)),
    email: v.pipe(v.string(), v.nonEmpty(), v.email()),
    password: v.pipe(v.string(), v.minLength(8, 'Password must be at least 8 characters long.')),
    confirmPassword: v.pipe(v.string(), v.nonEmpty('Please confirm your password.')),
    acceptTerms: v.pipe(
      v.boolean(),
      v.check((accepted) => accepted, 'You must accept the terms.')
    ),
  }),
  v.forward(
    v.check((input) => input.password === input.confirmPassword, 'The two passwords do not match.'),
    ['confirmPassword']
  )
)

const form = useForm({
  validationSchema: toTypedSchema(schema),
  initialValues: {
    username: '',
    email: '',
    password: '',
    confirmPassword: '',
    acceptTerms: false,
  },
})

const fields = createFormFields(() => [
  {
    type: INPUT_TYPES.TEXT,
    props: {
      name: 'username',
      label: 'Username',
      leadingIcon: 'ph:user',
      required: true,
    },
  },
  {
    type: INPUT_TYPES.TEXT,
    props: {
      name: 'email',
      label: 'Email',
      leadingIcon: 'ph:envelope',
      required: true,
    },
  },
  {
    type: INPUT_TYPES.PASSWORD,
    props: {
      name: 'password',
      label: 'Password',
      required: true,
    },
  },
  {
    type: INPUT_TYPES.PASSWORD,
    props: {
      name: 'confirmPassword',
      label: 'Confirm password',
      required: true,
    },
  },
  {
    type: INPUT_TYPES.CHECKBOX,
    props: {
      name: 'acceptTerms',
      label: 'I accept the terms and conditions',
    },
  },
])

const dialog = useDialog()

const onSubmit = form.handleSubmit(async (values) => {
  await dialog.success({
    title: `Welcome, ${values.username}!`,
    description: 'Your account was created.',
  })

  form.resetForm()
}, moveToError)

defineExpose({
  debug: computed(() => ({
    values: form.values,
    errors: form.errors.value,
  })),
})
</script>