Nuxt Form Validation: A Comprehensive Tutorial

Nuxt Form Validation: A Comprehensive Tutorial

·

3 min read

I'll recommend some popular validation packages for Nuxt.js and show you how to implement them.

The two most recommended validation packages for Nuxt.js are:

  1. Vee-Validate - Most popular, easy to use, and well maintained

  2. Zod - Type-safe validation, great TypeScript support

  3. Yup - Similar to Zod but more established

Let me show you how to implement validation using Vee-Validate, as it's the most commonly used:
First, install Vee-Validate:

npm install vee-validate @vee-validate/rules
Here's an example of a form with validation:

// components/RegisterForm.vue
<template>
  <div class="register-form">
    <Form @submit="onSubmit" :validation-schema="schema">
      <div class="form-group">
        <label for="username">Username</label>
        <Field 
          name="username" 
          type="text" 
          id="username"
          v-slot="{ field, errors }"
        >
          <input v-bind="field" class="form-input" />
          <span class="error" v-if="errors">{{ errors }}</span>
        </Field>
      </div>

      <div class="form-group">
        <label for="email">Email</label>
        <Field 
          name="email" 
          type="email" 
          id="email"
          v-slot="{ field, errors }"
        >
          <input v-bind="field" class="form-input" />
          <span class="error" v-if="errors">{{ errors }}</span>
        </Field>
      </div>

      <div class="form-group">
        <label for="password">Password</label>
        <Field 
          name="password" 
          type="password" 
          id="password"
          v-slot="{ field, errors }"
        >
          <input v-bind="field" class="form-input" />
          <span class="error" v-if="errors">{{ errors }}</span>
        </Field>
      </div>

      <div class="form-group">
        <label for="confirmPassword">Confirm Password</label>
        <Field 
          name="confirmPassword" 
          type="password" 
          id="confirmPassword"
          v-slot="{ field, errors }"
        >
          <input v-bind="field" class="form-input" />
          <span class="error" v-if="errors">{{ errors }}</span>
        </Field>
      </div>

      <button type="submit">Register</button>
    </Form>
  </div>
</template>

<script setup>
import { Form, Field } from 'vee-validate';
import * as yup from 'yup';
import { useAuthStore } from '~/stores/auth';

const auth = useAuthStore();

// Define validation schema
const schema = yup.object().shape({
  username: yup
    .string()
    .required('Username is required')
    .min(3, 'Username must be at least 3 characters')
    .max(20, 'Username must be less than 20 characters'),
  email: yup
    .string()
    .required('Email is required')
    .email('Must be a valid email'),
  password: yup
    .string()
    .required('Password is required')
    .min(8, 'Password must be at least 8 characters')
    .matches(/[0-9]/, 'Password must contain at least one number')
    .matches(/[A-Z]/, 'Password must contain at least one uppercase letter'),
  confirmPassword: yup
    .string()
    .required('Please confirm your password')
    .oneOf([yup.ref('password')], 'Passwords must match')
});

const onSubmit = async (values) => {
  try {
    await auth.register(values);
    // Handle successful registration
  } catch (error) {
    // Handle registration error
  }
};
</script>

<style scoped>
.register-form {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
}

.form-group {
  margin-bottom: 1rem;
}

.form-input {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.error {
  color: red;
  font-size: 0.875rem;
  margin-top: 0.25rem;
}

button {
  width: 100%;
  padding: 0.75rem;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #45a049;
}
</style>
  • To use Vee-Validate globally in your Nuxt.js application, create a plugin:

      // plugins/vee-validate.js
      import { defineRule } from 'vee-validate';
      import { required, email, min, max } from '@vee-validate/rules';
    
      export default defineNuxtPlugin(() => {
        // Define global validation rules
        defineRule('required', required);
        defineRule('email', email);
        defineRule('min', min);
        defineRule('max', max);
      });
    

    Then add it to your nuxt.config.js:

      export default defineNuxtConfig({
        plugins: ['~/plugins/vee-validate.js']
      });
    
  • Alternative Option - Using Zod:

      // Example of Zod validation schema
      import { z } from 'zod';
    
      const userSchema = z.object({
        email: z.string().email('Invalid email address'),
        password: z
          .string()
          .min(8, 'Password must be at least 8 characters')
          .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
          .regex(/[0-9]/, 'Password must contain at least one number'),
        username: z
          .string()
          .min(3, 'Username must be at least 3 characters')
          .max(20, 'Username must be less than 20 characters')
      });
    

Key features of Vee-Validate:

  1. Form-level and field-level validation

  2. Custom validation rules

  3. Async validation support

  4. Built-in rules for common validations

  5. Good integration with Vue 3 and Nuxt

  6. Cross-field validation (like password confirmation)