Theme

Advanced Guides

Form & Input Validation

Form and input validation are essential for ensuring data integrity, improving user experience, and maintaining application security. Validation should occur on both the client-side (for immediate feedback) and the server-side (for security and data consistency).

Client-Side Validation

Native HTML Form Validation

For basic client-side validation, HTML5 offers built-in features that work out-of-the-box. These include attributes such as required, type, pattern, and minlength/maxlength. Using native form validation is sufficient for most use cases.

<form>
  <label for="firstName">First Name:</label>
  <input type="text" id="firstName" name="firstName" required minlength="2" maxlength="50" />
  <label for="lastName">Last Name:</label>
  <input type="text" id="lastName" name="lastName" required minlength="2" maxlength="50" />
  <label for="email">Email:</label>
  <input type="email" id="email" name="email" required />
  <button type="submit">Submit</button>
</form>

In this example:

  • The type="email" ensures the input is a valid email format.
  • The required attribute prevents the form from being submitted if the input is empty.

When the user submits the form, the browser automatically validates it and provides feedback without requiring custom JavaScript.

Advanced Styling

To enhance the styling of validation states, use the :user-invalid pseudo-class, which applies styles to invalid form controls.

Here’s an enhanced version using the :user-invalid pseudo-class for custom styling and showing/hiding an error message:

const Input = ({ name, label, ...rest }: InputProps) => (
  <>
    <input
      name={name}
      id={name}
      placeholder={label}
      class="peer w-full rounded border border-slate-200 px-3 py-2 placeholder-slate-300 [&:user-invalid]:border-red-500"
      {...rest}
    />
    <div class="mt-1 hidden text-sm text-red-500 peer-[&:user-invalid]:block">{label} is invalid</div>
  </>
);

This approach combines native validation with modern styling, giving users instant feedback while maintaining a clean UI.

Server-Side Validation

While client-side validation provides a great user experience, it is not secure because users can bypass it (e.g., by disabling JavaScript or tampering with requests). Server-side validation is essential to:

  • Ensure data integrity.
  • Prevent malicious input.
  • Handle edge cases not covered by client-side validation.

For robust server-side validation, use Fastify's built-in JSON Schema validation. JSON Schema allows you to define and enforce strict validation rules for incoming data.

const requestBodySchema = {
  type: 'object',
  properties: {
    firstName: { type: 'string', minLength: 2, maxLength: 50 },
    lastName: { type: 'string', minLength: 2, maxLength: 50 },
    email: { type: 'string', format: 'email' }
  },
  required: ['firstName', 'lastName', 'email']
};

In src/plugins/pages.tsx you can add the JSON Schema to the route registration:

localePrefixedRouter.post('/my-new-page', { schema: { body: requestBodySchema } }, (_request, reply) =>
  reply.render(<MyNewPage />)
);
Previous
Internationalization (i18n)