Skip to content

Form

Collect and validate form data.

Usage

Use the Form component to validate form data using schema libraries such as Yup, Zod, Joi, Valibot, or your own validation logic.

It works with the FormGroup component to display error messages around form elements automatically.

The form component requires two props:

  • state - a reactive object holding the form's state.
  • schema - a schema object from Yup, Zod, Joi, or Valibot.

INFO

Note that no validation library is included by default, so ensure you install the one you need.

Schema

You can provide a schema from Yup, Zod or Joi, Valibot through the schema prop to validate the state. It's important to note that none of these libraries are included by default, so make sure to install the one you need.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { object, string, InferType } from 'yup'

const schema = object({
  email: string().email('Invalid email').required('Required'),
  password: string()
      .min(8, 'Must be at least 8 characters')
      .required('Required')
})

type Schema = InferType<typeof schema>

const state = ref({
  email: undefined,
  password: undefined
})

async function submit (event) {
  // Do something with event.data
  console.log(event.data)
}
</script>

<template>
  <s-form
      :schema="schema"
      :state="state"
      @submit="submit"
      class="space-y-4"
  >
    <s-form-group label="Email" name="email">
      <s-input v-model="state.email" />
    </s-form-group>

    <s-form-group label="Password" name="password">
      <s-input v-model="state.password" type="password" />
    </s-form-group>

    <s-button type="submit">
      Submit
    </s-button>
  </s-form>
</template>

Custom validation

Use the validate prop to apply your own validation logic.

The validation function must return a list of errors with the following attributes:

  • message - Error message for display.
  • path - Path to the form element corresponding to the name attribute.

INFO

Note that it can be used alongside the schema prop to handle complex use cases.

vue
<script setup lang="ts">
import {reactive} from "vue";

const state = reactive({
  email: undefined,
  password: undefined
})

const validate = (state: any) => {
  const errors = []
  if (!state.email) errors.push({path: 'email', message: 'Required'})
  if (!state.password) errors.push({path: 'password', message: 'Required'})
  return errors
}

async function onSubmit(event) {
  // Do something with data
  console.log(event.data)
}
</script>

<template>
  <SForm :validate="validate" :state="state" class="space-y-4" @submit="onSubmit">
    <SFormGroup label="Email" name="email">
      <SInput v-model="state.email"/>
    </SFormGroup>

    <SFormGroup label="Password" name="password">
      <SInput v-model="state.password" type="password"/>
    </SFormGroup>

    <SButton type="submit">
      Submit
    </SButton>
  </SForm>
</template>

Released under the MIT License.