Validate your form using Sveltekit, Tailwindcss, Felte and Yup

Hessel
8 min readJan 13, 2023

--

Form validation is important in web development, as it helps to ensure that the data that is submitted through a form is accurate and complete. In this post, you will learn how to implement form validation in a Sveltekit application using TailwindCSS, the form validation library yup, and the form validation library Felte. By the end of this tutorial, you will have a solid understanding of how to implement form validation in your own Sveltekit projects.

Create a Sveltekit project

The first step in implementing form validation using Svelte, TailwindCSS, Felte, and yup is to set up your Sveltekit project and install the necessary dependencies. If you already have a Sveltekit project, you can skip this.

To set up a new Sveltekit project, first, make sure that you have Node.js and npm installed on your machine. Then, open a terminal window and run the following command to create a new project:

npm create svelte@latest my-app

then you will get to see the following in your terminal:

Terminal

In this tutorial, we will go for the second option named “Skeleton project”.

Then they will ask you for a bunch of options like do you want to add type checking, ESLint, prettier for code formatting, browser testing and Vitest for unit testing. For this tutorial, I selected no for every option, since we don’t need it right now:

Terminal options

Now that you have created your Sveltekit project, head over to that directory and run the following commands:

#install the dependencies
npm install

#Serve your project
npm run dev

If everything went correct, you should now have a working Sveltekit project.

Installing TailwindCSS

To use Tailwindcss in our project, there are a few steps we need to do. First we need to install Tailwindcss along with Postcss and Autoprefixer. We can do this using the following command:

npm install -D tailwindcss postcss autoprefixer

Now that Tailwind is installed, we are going to create a Tailwind config using the following command:

npx tailwindcss init tailwind.config.cjs -p

Now that we have created a Tailwindcss config, we need to update our svelte.config.js. We need to paste the following code in there:

import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter()
},
preprocess: vitePreprocess()
};

export default config;

Now you might get an error about adapter. This can be fixed by running:

npm install @sveltejs/adapter-auto     

Then we need to update our Tailwind config. We need to paste the following code:

/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {}
},
plugins: []
};

After updating our Tailwindcss config, we need to create a CSS file named app.css in the src folder and paste the following code:

@tailwind base;
@tailwind components;
@tailwind utilities;

And finally, we need to create a +layout.svelte in the routes folder that is located in the src folder. We will paste the following code in there:

<script>
import "../app.css";
</script>

<slot />

If everything went correct, Tailwindcss should now be installed. To see if it works, you should create a +page.svelte (if you don’t have it already) and paste the following code:

<h1 class="text-3xl font-bold underline">
Hello world!
</h1>

Now you should run npm run dev, and you are supposed to see a h1 in bold text with an underline that says Hello world.

Install Felte and Yup

Now that we have installed Tailwindcss, it’s time to install Felte and Yup. You can do that by running the following commands:

#install felte
npm install felte

#install yup
npm install yup

Once that is installed, it is time to create a form using Tailwindcss

Creating a form with TailwindCSS

<div class="flex flex-col items-center justify-center w-screen h-screen bg-gray-200 text-gray-700">
<!-- form here -->
</div>

We will start with creating a flexbox by applying the class “flex” to a parent div. By applying the flex class to the parent div, we are creating a flex container and all the child elements will be flex items. This allows us to stack items vertically using “flex-col”, align child elements along the center of the container’s cross axis using “items-center” and use the “justify-center” to justify the items along the center of the container’s main axis. The “w-screen” and “h-screen” classes make the parent div take up the full width and height of the screen.

<div class="flex flex-col items-center justify-center w-screen h-screen bg-gray-200 text-gray-700">
<h1 class="font-bold text-2xl">Tailwind svelte validation</h1>

<form action="#" method="post" class="flex flex-col bg-white rounded shadow-lg p-12 mt-12">

</form>
</div>

Now that we have created a flex container, we can start by adding a simple title above the form and create the form itself. To style the form, we are going to add the “flex” and “flex-col” classes to stack everything inside the form vertically. To create some space, we will add some padding using “p-12” and move the form down a little bit using “mt-12”. And finally, we will add some shadow to make it look like it’s floating using “shadow-lg”.

It is now time to add labels, input fields, a place for the error messages, a submit button and a forgot password / sign up (just to make it look like a login form) to our form:

<div class="flex flex-col items-center justify-center w-screen h-screen bg-gray-200 text-gray-700">
<h1 class="font-bold text-2xl">Tailwind svelte validation</h1>

<form use:form on:submit|preventDefault action="#" method="post" class="flex flex-col bg-white rounded shadow-lg p-12 mt-12">
<label class="font-semibold text-xs" for="email">Email</label>
<input class="flex items-center h-12 px-4 w-64 bg-gray-200 mt-2 rounded focus:outline-none focus:ring-2" name="email" type="email" />
<!-- error message -->
<span class="text-red-500 text-sm"></span>
<!-- -->
<label class="font-semibold text-xs mt-3" for="password">Password</label>
<input class="flex items-center h-12 px-4 w-64 bg-gray-200 mt-2 rounded focus:outline-none focus:ring-2" name="password" type="password" />
<!-- error message -->
<span class="text-red-500 text-sm"></span>
<!-- -->
<button class="flex items-center justify-center h-12 px-6 w-64 bg-blue-600 mt-8 rounded font-semibold text-sm text-blue-100 hover:bg-blue-700">Login</button>
<div class="flex mt-6 justify-center text-xs">
<a class="text-blue-400 hover:text-blue-500" href="#">Forgot Password</a>
<span class="mx-2 text-gray-300">/</span>
<a class="text-blue-400 hover:text-blue-500" href="#">Sign Up</a>
</div>
</form>
</div>

Your form should now look like this:

Tailwind form

The validation

We are now finally at the point where we are going to add the validation. For that to work, we need to create a script tag and import necessary libraries:

<script>
import { createForm } from "felte";
import * as yup from "yup";
</script>

Now that we have imported the libraries, we are going to create a schema using Yup:

<script>
import { createForm } from "felte";
import * as yup from "yup";

const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().required(),
});
</script>

Our schema is an object that has two properties named “email” and “password”. The string method makes sure that the input is actually a string, the email method checks whether it is a valid email format or not and the required method make sure that the input fields can’t be empty.

Now we will actually validate our values from the form using the createForm method from felte. This method accepts a function named “validation”. This function accepts a parameter named values that contains the submitted values from the form:

<script>
import { createForm } from "felte";
import * as yup from "yup";

const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().required(),
});

const { form, errors } = createForm({
validate: async (values) => {

}
});
</script>

In here, we can validate our schema with Yup. Yup has a method named “validate” that accepts our values and also has a property abortEarly which is a boolean. This will return validation on the first error rather than after all validations run. You can set is to true if you want, but for now we will set to false, so we can display all validation errors:

<script>
import { createForm } from "felte";
import * as yup from "yup";

const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().required(),
});

const { form, errors } = createForm({
validate: async (values) => {
try {
await schema.validate(values, { abortEarly: false });
} catch(err) {
//
}
}
});
</script>

To get our error messages, we need to iterate over the inner array. We can do that by using the “reduce” method. This will create an error object for us that contains properties named after the fields with error message:

<script>
import { createForm } from "felte";
import * as yup from "yup";

const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().required(),
});

const { form, errors } = createForm({
validate: async (values) => {
try {
await schema.validate(values, { abortEarly: false });
} catch(err) {

const errors = err.inner.reduce((res, value) => ({
[value.path]: value.message,
...res,
}), {});

return errors;
}
}
});
</script>

Now we need to add use:form and on:submit|preventDefault on our form like so:

<form use:form on:submit|preventDefault action="#" method="post" class="flex flex-col bg-white rounded shadow-lg p-12 mt-12">
<!-- The rest of our form -->
</form>

The use:form will handle the form-related tasks like validation, submission, and error handling. We will also add on:submit|preventDefault. By default, when you submit a form, the browser will navigate to the URL that is specified in the action attribute, which will cause a page reload. In order to display validation messages, we must prevent this behavior by adding the prevent default.

And finally we will display the error messages in our HTML. The error messages are available in the error object:

<form use:form on:submit|preventDefault action="#" method="post" class="flex flex-col bg-white rounded shadow-lg p-12 mt-12">
<label class="font-semibold text-xs" for="email">Email</label>
<input class="flex items-center h-12 px-4 w-64 bg-gray-200 mt-2 rounded focus:outline-none focus:ring-2" name="email" type="email" />
{#if $errors.email}
<span class="text-red-500 text-sm">{$errors.email}</span>
{/if}
<label class="font-semibold text-xs mt-3" for="password">Password</label>
<input class="flex items-center h-12 px-4 w-64 bg-gray-200 mt-2 rounded focus:outline-none focus:ring-2" name="password" type="password" />
{#if $errors.password}
<span class="text-red-500 text-sm">{$errors.password}</span>
{/if}
<button class="flex items-center justify-center h-12 px-6 w-64 bg-blue-600 mt-8 rounded font-semibold text-sm text-blue-100 hover:bg-blue-700">Login</button>
<div class="flex mt-6 justify-center text-xs">
<a class="text-blue-400 hover:text-blue-500" href="#">Forgot Password</a>
<span class="mx-2 text-gray-300">/</span>
<a class="text-blue-400 hover:text-blue-500" href="#">Sign Up</a>
</div>
</form>

That’s it, that is how you validate your form using felte and yup. Now one more thing for yup. To display custom error messages in yup, you can pass a string as an argument:

const schema = yup.object({
email: yup.string().email('This field must be an email').required('This field is required'),
password: yup.string().required('This field is required'),
});

The full code is available on github: https://github.com/Heesel/Sveltekit-felte-yup-tailwind

--

--

Hessel

Web developer sharing knowledge on Web Development through Medium articles. From beginner to advanced topics, follow me to improve your skills and stay current.