Nefe James Nefe is a frontend developer who enjoys learning new things and sharing his knowledge with others.

Top form validation libraries in Svelte

12 min read 3637

Introduction

Form validation is hard. That’s why there are several libraries that handle form validation for us, so we do not have to set up custom validation solutions ourselves. Every project has different form validation needs and there is no one-size-fits-all solution.

Therefore, in this article, I will walk you through the most popular and active Svelte form validation libraries to help you choose which one to use in your next project. I chose these seven libraries based on the number of GitHub stars and npm downloads they have, so you can be confident that the library you choose is popular among other devs.

The libraries are as follows:

  1. Svelte forms lib
  2. Felte
  3. Svelte Use Form
  4. Svelte Final Form
  5. Svelte-yup
  6. Sveltik
  7. Sveltejs-forms

Svelte forms lib

Svelte forms lib is a Formik-inspired library for building forms easily in a Svelte project. While it does not come with many features, It handles the basic scenarios of validating forms and displaying errors well. Svelte forms lib is a good, light library to use when setting up basic form validation.

Setup

Run the command below in your terminal to install the library:

npm i svelte-forms-lib

The core of integrating Svelte forms lib into a form lies in the createForm function, as seen here:

<script>
  import { createForm } from "svelte-forms-lib";
  import * as yup from "yup";

  const { form, errors, state, handleChange, handleSubmit } = createForm({
    initialValues: {
      name: "",
      email: ""
    },
    validationSchema: yup.object().shape({
      name: yup.string().required(),
      email: yup.string().email().required()
    }),
    onSubmit: values => {
      alert(JSON.stringify(values));
    }
  });
</script>

<form on:submit={handleSubmit}>
  <input
    id="name"
    name="name"
    on:change={handleChange}
    on:blur={handleChange}
    bind:value={$form.name}
    placeholder="name"
  />
  {#if $errors.name}
    <small>{$errors.name}</small>
  {/if}

  <input
    id="email"
    name="email"
    on:change={handleChange}
    on:blur={handleChange}
    bind:value={$form.email}
    placeholder="email"
  />
  {#if $errors.email}
    <small>{$errors.email}</small>
  {/if}

  <button type="submit">submit</button>
</form>

createForm gives us access to useful form helps like handleChange and handleSubmit, among others. We will need these helper functions to set up the form.

Aside from helper functions, Svelte forms lib exposes observable values that give us information on the current state of the form. You can check out the list of available observables here.

We pass a config object as an argument to createForm. Here, we define the initialValues of the form and an onSubmit handler that will handle the form submission. Having configured createForm, we need to hook the profile form up to Svelte forms lib, so it can track the form values and handle the submission.

We made a custom demo for .
No really. Click here to check it out.

To do that, we pass the handleSubmit helper to the form element. We also pass handleChange to the input fields and bind their values to the form observable.

Validation

Svelte forms lib supports validation with Yup through a validationSchema prop, which takes in a schema object. Svelte forms lib also supports custom validation.

Developer experience

As a library inspired by Formik, Svelte forms lib has a similar API. A developer coming from a React background will find this library easy to work with.

Another developer experience plus is that, like Formik, Svelte forms lib provides custom components:

<script>
  import { Form, Field, ErrorMessage, Select } from "svelte-forms-lib";
  import schema from "./schema";

  const formProps = {
    initialValues: {},
    validationSchema: schema,
    onSubmit: (values) => {
      alert(JSON.stringify(values));
    },
  };
</script>
<div class="container">
  <h1>Registration Form</h1>
  <Form {...formProps}>
    <div>
      <Field type="text" name="name" placeholder="Name" />
      <ErrorMessage name="name" />
    </div>
    <div>
      <Field type="email" name="email" placeholder="Email" />
      <ErrorMessage name="email" />
    </div>     

      <button type="submit">Submit</button>
  </Form>
</div>

It provides Form, Field, Select, and ErrorMessage components. Using these custom components will reduce the boilerplate and make the form code very concise. We no longer need to conditionally render the error for each field, because ErrorMessage handles it for us.

Svelte forms lib has easy-to-understand and beginner-friendly documentation. The docs provide several examples that cover different use cases and code snippets that can easily be copied.

Felte

Felte is a simple form library for Svelte that aims to help make form management and validation easy. Felte is packed with features that cover several form handling and validation use cases. Due to the several integrations available with Felte, it can be overwhelming to work with. Hence, I advise you use it only for complex scenarios like multistep forms.

Setup

Run the command below in your terminal to install the library:

npm i felte

Felte provides a createForm function that we can use to set up forms like so:

<script>
  import { createForm } from "felte";
  import { validator } from "@felte/validator-yup";
  import * as yup from "yup";
  const schema = yup.object({
    email: yup.string().email().required(),
    name: yup.string().required(),
  });
  const { form, errors } = createForm({
    extend: validator,
    validateSchema: schema,
    onSubmit: async (values) => {
      alert(JSON.stringify(values));
    },
  });
</script>

<form use:form on:submit|preventDefault>
  <input type="text" name="name" />
  {#if $errors.name}
    <span class="error">{$errors.name}</span>
  {/if}
  <input type="email" name="email" />
  {#if $errors.email}
    <span class="error">{$errors.email}</span>
  {/if}
  <button type="submit">Submit</button>
</form>

From createForm, we pull out a form action that we pass to HTML’s form element through Svelte’s use directive. This is all you need to integrate Felte into your forms and make them form reactive.

createForm accepts a config object where we set up validation with Yup, and define an onSubmit function that handles the form submission.

Validation

With Felte, you can spin up your own custom validation or use libraries like Yup, Zod, or Superstruct.

In the code snippet above, we used Yup. We access the errors object from createForm and conditionally display the error related to each input field.

Developer experience

Felte is a beginner-friendly library full of plenty of features and options. I love the fact that it supports validation with Yup, though we have to install a third party library, @felte/validator-yup, to set it up.

Felte has extremely detailed, organized, and easy-to-understand documentation filled with demos and code snippets that cover several use cases.

Svelte Use Form

Svelte Use Form is an easy-to-use form library that handles the validation and state of each input field, and handles basic form validation and integration well. However, it does not provide out-of-the-box handling for advanced cases like multistep forms. It supports inputs, textarea, selects, radio buttons, and checkboxes.

Setup

Run the command below in your terminal to install the library:

npm i -D svelte-use-form

Svelte Use Form provides a useForm function we can hook to HTML’s form element through Svelte’s use directive:

<script>
  import {useForm, Hint, HintGroup, validators, minLength,email,required} from "svelte-use-form";

  const form = useForm();

  let formData = {}; //we store the form values here

  const onSubmit = () => {
    $form.touched = true;
    if ($form.valid) {
      alert(JSON.stringify(formData));
    }
  };
</script>

<form use:form>
 <div class="form-row">
      <label for="name">Name</label>
      <input
        type="name"
        name="name"
        bind:value={formData.name}
        use:validators={[required, minLength(5)]}
      />
      <HintGroup for="name">
        <Hint on="required">Name is required</Hint>
        <Hint on="minLength" hideWhenRequired let:value>
          Name requires at least {value} characters.</Hint
        >
      </HintGroup>
    </div>

    <div class="form-row">
      <label for="email">Email</label>
      <input
        type="email"
        name="email"
        use:validators={[required, email]}
        bind:value={formData.email}
      />
      <HintGroup for="email">
        <Hint on="required">Email is required</Hint>
        <Hint on="email" hideWhenRequired>Email is not valid</Hint>
      </HintGroup>
    </div>

    <button type="submit" on:click|preventDefault={onSubmit}>Sign In</button>
</form>

One thing I love about using Svelte Use Form is how easy it is to integrate with forms. We can import useForm, Hint, HintGroup, validators, minLength , email, and required.

useForm is used in registering the form with Svelte Use Form. Hint and HintGroup are used to display the validation errors for each field. minLength, email, and required are the validation checks we pass to validators.

Validation

Svelte Use Form exports a validators function that we can use to add validation to the input fields. We link validators to the input fields using the use directive.

For the name input, we set it to required, and its minLength to five characters. For the email input, we set it to required to check that the email must be valid.

Developer experience

Svelte Use Form does not provide a submit handler that can be used to handle form submission. Also, there is no values object or something similar where the form values are stored, so we have to bind the values of the input fields to the formData object.

As I write this article, there is no way to style error messages when using Hint or HintGroup. If we wanted to style the error messages, we will have to do so this way:

{#if $form.title?.touched && $form.title?.errors.minLength}
   <span class="error">The title requires at least {$form.title.errors.minLength} characters.</span>
{/if} 

Svelte Use Form has solid, clear documentation. Some demos are provided that show how the library works with different types of input fields, which makes Svelte Use Form easier to work with.

Svelte Final Form

Svelte Final Form is a Svelte wrapper for Final Form, a framework-agnostic form library.

Setup

Run the command below in your terminal to install the library:

npm i --save final-form svelte-final-form

Svelte Final Form has a similar API to React Final Form. If you’re familiar with that, you will find this library easy to work with:

<script>
  import { Form, Field } from "svelte-final-form";
  const initialValues = {
    name: "Nefe",
    email: "[email protected]",
  };
  const onSubmit = (values) => {
    alert(JSON.stringify(values));
  };
  const validate = (values) => {
    const errors = {};
    if (!values.name) {
      errors.name = "Name is required";
    }
    if (!values.email) {
      errors.email = "Email is Required";
    } else if (!/^[^\[email protected]][email protected][^\[email protected]]+\.[^\[email protected]]+$/.test(values.email)) {
      errors.email = "Invalid emaill address";
    }
    return errors;
  };
</script>
<Form {onSubmit} {validate} {initialValues} let:form let:state>
  <form on:submit|preventDefault={form.submit}>
    <Field name="name" let:input let:meta>
      <label for="name">Name</label>
      <input
        name={input.name}
        on:blur={input.onBlur}
        on:focus={input.onFocus}
        on:input={(e) => input.onChange(e.target.value)}
        type="text"
        value={input.value}
      />
      {#if meta.touched && meta.error}
        <span class="error">{meta.error}</span>
      {/if}
    </Field>
    <Field name="email" let:input let:meta>
      <label for="email">Name</label>
      <input
        name={input.email}
        on:blur={input.onBlur}
        on:focus={input.onFocus}
        on:input={(e) => input.onChange(e.target.value)}
        type="text"
        value={input.value}
      />
      {#if meta.touched && meta.error}
        <span class="error">{meta.error}</span>
      {/if}
    </Field>
    <button type="submit" disabled={state.submitting}>Submit</button>
  </form>
</Form>

The Form component is a special wrapper provided by Svelte Final Form that manages the state of the form. Form passes the form and state components to its children through the let directive.

Similar to Form, Field passes input and meta components to its input field children.
input contains the necessary methods like onBlur, onFocus, and onChange that we need to pass to the input fields.
The meta object contains information on the state of the form. We determine whether the inputs have been touched or if they have errors from meta.

Validation

Svelte Final Form does not support validation with Yup or other object validation schemas, so we have to create a custom validation ourselves.

The validate function handles the validation for the form. The onSubmit function will be called with the values of your form when the user submits the form and all validation passes.

Developer experience

Svelte Final Form makes form validation awesome and fun. Not only does it “just work,” but it makes it easy to understand how the code works.

It has a beginner-friendly API, and as far as form submission goes, Form has an onSubmit prop that takes in a submit function. We don’t have to track the form data, because Svelte Final Form handles that for us.

Svelte Final Form does not have an in-depth documentation library because it does not need one; it is easy to understand. However, it would be awesome if more demos were made available.

Svelte-yup

Svelte-yup is a Svelte component library used to validate forms with Yup. While svelte-yup supports form validation with Yup, you will have to create the validation integration, unlike other libraries that handle it for you. Having a deeper knowledge of Yup may be needed for svelte-yup to be fully maximized.

Setup

Run the command below in your terminal to install the library:

npm i svelte-yup yup

Svelte-yup provides Form and Message components we can use to integrate it into our forms:

<script>
  import * as yup from 'yup';
  import {Form, Message} from 'svelte-yup';
  let schema = yup.object().shape({
    name: yup.string().required().max(30).label("Name"),
    email: yup.string().required().email().label("Email address"),
  });

  let fields = {name: "", email: ""};
  let submitted = false;
  let isValid;

  function formSubmit(){
    submitted = true;
    isValid = schema.isValidSync(fields);
    if(isValid){
      alert(JSON.stringify(fields));
    }
  }
</script>

<Form {schema} {fields} submitHandler={formSubmit} {submitted}>
  <input type="text" bind:value={fields.name} placeholder="Name">
  <Message name="name" />
  <input type="text" bind:value={fields.email} placeholder="Email address">
  <Message name="email" />
  <button type="submit">Submit</button>
</Form>

Validation

Svelte-yup relies on Yup to handle form validation. When formSubmit is called, we set submitted to true. However, the core validation takes place in schema.isValidSync(fields). We store the result of this validation check in the isValid variable, and if it is valid, we submit the form data.

Developer experience

There is no built-in way to check the form and validation states, so we have to set up submitted and isValid variables for them.

Svelte-yup comes with Form and Message components, and Message handles displaying the form errors for us, a plus for the developer experience.

Because svelte-yup handles validation with Yup, people familiar with Yup don’t need to learn a new validation syntax. This makes it easy to work with.

The documentation for svelte-yup is well-structured and detailed. The docs provide demos and even show how to use it with Material UI and Bootstrap custom form fields.

Sveltik

Similar to Svelte forms lib, Sveltik is also a Formik-inspired library for handling forms in Svelte. Being a Formik-inspired library, you can learn possible ways Sveltik has been used based on how Formik was used. You can use the Formik examples as guides on how to integrate Sveltik into your app.

Setup

Run the command below in your terminal to install the library:

npm i sveltik

Sveltik comes with Sveltik, Form, Field and ErrorMessage custom components, which we can use in setting up forms like so:

<script>
  import { Sveltik, Form, Field, ErrorMessage } from 'sveltik'
  let initialValues = {
    name: '',
    email: '',
  }
  let validate = values => {
    const errors = {}
    if(!values.name){
      errors.name = "Name is required"
    }
    if (!values.email) {
        errors.email = 'Email is required'
    } else if (!/^[A-Z0-9._%+-][email protected][A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
        errors.email = 'Invalid email address'
        }
      return errors
    }
    let onSubmit = (values) => {
      alert(JSON.stringify(values))
    }
</script>
<Sveltik {initialValues} {validate} {onSubmit}>
  <Form>
    <div class="form-row">
      <Field type="text" name="name" />
      <ErrorMessage name="name" as="span" />
    </div>
    <div class="form-row">
      <Field type="email" name="email" />
      <ErrorMessage name="email" as="span" />
    </div>

    <button type="submit">Submit</button>
  </Form>
</Sveltik>

In the Sveltik component, we pass in initialValues, validate, and onSubmit props.
initialValues is an object that holds the initial values of the respective form fields, validate accepts a function that handles the form validation, and onSumbit takes a function that handles the form submission. This runs only when there are no errors present in the form fields.

Form is a small wrapper around an HTML <form> element that automatically hooks into Sveltik’s handleSubmit and handleReset. ErrorMessage renders the error message of a given field if that field has been visited and there is an error.

Field automatically links the input’s onChange, onBlur, and value attributes to Formik’s handleChange, handleBlur, and values object, respectively. It uses the name prop to match up with the state and automatically keeps the state in sync with the input value. It renders an HTML input field by default.

Validation

Sveltik does not provide out-of-the-box Yup integration like Svelte forms lib does with its validationSchema prop. This means we have to create custom validation ourselves, like in the code snippet above.

In the validate function, we run validation checks for the name and email input fields, and based on the error, update the errors object accordingly.

Developer experience

Because Sveltik is a Formik-inspired library, anyone who has experience using Formik will find it easy to work with. The Field and ErrorMessage components abstract the repetitive boilerplate code like setting up onBlur, onChange, and tracking the value for each field.

Not only does this make Sveltik a beginner-friendly library, but also one that provides a great developer experience.

Sveltik has an easy-to-understand documentation. However, it would be nice to see more demos that cover different scenarios.

Sveltejs-forms

With sveltejs-forms, we can make declarative forms in Svelte. It provides Input, Select, and Choice to make integration easier. You won’t need to set up onChange, onBlur, and other form event handlers because the components abstract those handlers.

Setup

Run the command below in your terminal to install the library:

npm i sveltejs-forms

I love how straightforward working with sveltejs-forms is. I can tell that a lot of thought was put into developing this library; it provides custom form, input, select, and checkbox components we can use to set up forms:

<script>
  import { Form, Input } from "sveltejs-forms";
  import * as yup from "yup";
  function handleSubmit({ detail: { values, setSubmitting, resetForm } }) {
    alert(JSON.stringify(values));
    setSubmitting(false);
    resetForm({ name: "", email: "" });
  }
  let schema = yup.object().shape({
    name: yup.string().required().label("Name"),
    email: yup.string().required().email().label("Email address"),
  });
</script>
<Form
  {schema}
  validateOnBlur={false}
  validateOnChange={false}
  on:submit={handleSubmit}
>
  <Input name="name" type="text" label="Name" placeholder="Name" />
  <Input name="email" label="Email Address" placeholder="Email" />
  <button type="submit">Submit</button> 
</Form>

Here, we set up the input fields by passing in the necessary name and type props to the Input component. The Form component accepts validateOnBlur and validateOnChange props where we define when the validation should run.

We set up a handleSubmit function that we pass to the Form‘s on:submit event. That’s all it takes to set up a basic integration!

Validation

Sveltejs-forms supports validation with Yup. Form has a schema prop, where we pass the validation schema we define for the input fields. The name for each schema we define must correspond to each input field’s name attribute. With that, Form tracks the validity and errors of each field.

What about displaying errors? The Form and Input components handle that for us. Form doesn’t just track the validity and errors of each field, it also creates a context where an errors object is stored. The Input component accesses that errors object, and conditionally displays any error that exists in a given field.

Developer experience

The fact that sveltejs-forms provides custom components that abstract dealing with things like on:change, on:blur, on:input, and setting the value of inputs for us is a huge developer experience plus. This makes setting up forms not only easy, but fast. The form data is tracked and stored for us, so we don’t have to bind the inputs and store the data ourselves.

We do, however, have to manually reset the input fields. If we had 15 inputs, that would be repetitive and tedious. It would be nice if there was a resetForm method, or something similar, that can be called to reset the input fields for us.

Sveltejs-forms has a straightforward documentation. It is brief because it’s a straightforward library that is easy to get started with. It also covers how to work with custom components.

Overview of Svelte form validation libraries

GitHub stars Weekly npm downloads Minified + Gzipped bundle size Yup integration Documentation
Svelte forms lib 331 1,148 5.2kb Yes Great
Felte 158 771 4kb Yes Great
Svelte Use Form 91 878 3.5kb No Good
Svelte Final Form 32 131 5.6kb No Basic
svelte-yup 18 81 4.1kb Yes Great
Sveltik 165 50 14.4kb No Good
sveltejs-forms 179 351 8kb Yes Good

Conclusion

In this article, we covered the top form validation libraries in Svelte. So far, Svelte forms lib has met my form handling and validation needs, and I always use it when I can.

At the end of the day, each library is great in its own way. When deciding which library to use in the future, check the metrics we discussed and weigh them against the goals and requirements of your app.

Nefe James Nefe is a frontend developer who enjoys learning new things and sharing his knowledge with others.

Leave a Reply