NashTech Blog

Table of Contents

🔰 Introduction to Svelte

Svelte is a modern JavaScript framework for building fast, reactive web applications. Unlike traditional frameworks like React or Vue, Svelte shifts much of the work to compile time—resulting in smaller, faster runtime code with minimal overhead.

One of the most powerful and elegant aspects of Svelte is how it handles forms. Thanks to Svelte’s reactivity and simple syntax, working with form inputs feels natural and expressive.

📝 Form in Svelte

Creating a form in Svelte is just like writing standard HTML, but enhanced with reactive bindings and event handling. Here’s a basic example:

<form method="POST" onsubmit={handleSubmit}>
    <input name="title" placeholder="Title" />
    <input name="author" placeholder="Author" />
    <input name="code" placeholder="Code" />
    <input name="year" type="number" placeholder="Year" />
    <button type="submit">Save</button>
</form>

🔗 Binding Data

In Svelte, two-way data binding is built in and intuitive. You can bind form inputs to variables using the bind: directive.

<script>
  let title = "";
  let author = "";
</script>
<input name="title" bind:value={title} placeholder="Title" />
<input name="author" bind:value={author} placeholder="Author" />

This way, any change in the input field updates the variable, and vice versa.

You can use bind:checked, bind:group, bind:files, etc., depending on the input type.

🌱 Progressive Enhancement

SvelteKit promotes progressive enhancement by making your forms work even when JavaScript is disabled—thanks to built-in support for traditional form submissions via form actions.

When you define an action function in your +page.server.js or +page.server.ts, your form will:

  • Submit via HTTP POST by default

  • Gracefully degrade to full-page reload if JavaScript is unavailable.

  • Enhance to a fast, JavaScript-driven experience when JS is present.

The easiest way to progressively enhance a form is to add the use:enhance action

<script lang="ts">
    import { enhance } from '$app/forms';
</script>

<form method="POST" action="?/create" use:enhance>
    <input name="title" bind:value={title} placeholder="Title" />
    <input name="author" bind:value={author} placeholder="Author" />
    <input name="code" bind:value={code} placeholder="Code" />
    <input name="year" type="number" bind:value={year} placeholder="Year" />
    <button type="submit">Save</button>
</form>

🚀 Form Action

In SvelteKit (Svelte’s full-stack framework), you can use form actions for progressive enhancement. Actions allow you to run logic on form submission on the server, then update the page with no JavaScript required.

On the server side (e.g., in +page.server.ts/js):

export const actions = {
    create: async ({ request }) => {
        const formData = await request.formData();

        const title = formData.get('title');
	const author = formData.get('author')';
	const code = formData.get('code');
	const year = Number(formData.get('year'));

       // Process and return result
    }
};

This provides a nice fallback and graceful progressive enhancement for forms.

✅ Form Validation

You can handle form validation on both the client and server sides.

Client-side Validation

On the client side (e.g., in +{%filename%}.svelte):

<script lang="ts">
    let title = "";
    let author = "";
    let code = "";
    let year = "";

    let errors = {
	title: '',
	author: '',
	code: '',
	year: ''
    };

    function validateForm() {
	let valid = true;
	errors = { title: '', author: '', code: '', year: '' };

	if (!title.trim()) {
		errors.title = 'Title is required.';
		valid = false;
	}

	if (!author.trim()) {
		errors.author = 'Author is required.';
		valid = false;
	}

	if (!code.trim()) {
		errors.code = 'Code is required.';
		valid = false;
	}

	if (!year || isNaN(year) || year < 0) {
		errors.year = 'Valid year is required.';
		valid = false;
	}

	return valid;
    }

    function onSubmit(event: SubmitEvent) {
	if (validateForm()) {
	    // Submit logic 
	}
    }
</script>

<form onsubmit={handleSubmit}>
    <input name="title" bind:value={title} placeholder="Title" />
    <input name="author" bind:value={author} placeholder="Author" />
    <input name="code" bind:value={code} placeholder="Code" />
    <input name="year" type="number" bind:value={year} placeholder="Year" />
    <button type="submit">Save</button>
</form>

Server-side Validation

If you’re using form actions , you can return errors back to the form. The fail function lets you return an HTTP status code (typically 400 or 422, in the case of validation errors) along with the data

// +page.server.js
import { fail } from '@sveltejs/kit';
export const actions = {
    create: async ({ request, cookies}) => {
        const userid = cookies.get('userid'); 
        const data = await request.formData();

        const title = data.get('title')?.toString() ?? '';
	const author = data.get('author')?.toString() ?? '';
	const code = data.get('code')?.toString() ?? '';
	const year = Number(data.get('year'));

        // Validation
        const errors: Record<string, string> = {};

        if (!title.trim()) errors.title = 'Title is required.';
	if (!author.trim()) errors.author = 'Author is required.';
	if (!code.trim()) errors.code = 'Code is required.';
	if (!year || isNaN(year) || year < 0) errors.year = 'Invalid year.';

        if (Object.keys(errors).length > 0) {
            return fail(400, {
                errors,
                values: { title, author, code, year }
            })
        }

        // Logic code after passing validation
    }
};
<!-- +page.svelte -->
<form method="POST" action={`?/${action}`} use:enhance>
    <div>
	<input name="title" bind:value={bookData.title} placeholder="Title" />
	{#if form?.errors?.title}<p class="error">{form.errors.title}</p>{/if}
    </div>
    <div>
	<input name="author" bind:value={bookData.author} placeholder="Author" />
	{#if form?.errors?.author}<p class="error">{form.errors.author}</p>{/if}
    </div>
    <div>
	<input name="code" bind:value={bookData.code} placeholder="Code" />
	{#if form?.errors?.code}<p class="error">{form.errors.code}</p>{/if}
    </div>
    <div>
	<input name="year" type="number" bind:value={bookData.year} placeholder="Year" />
	{#if form?.errors?.year}<p class="error">{form.errors.year}</p>{/if}
    </div>
    <button type="submit">Save</button>
</form>

🧩 Conclusion

Svelte makes form handling elegant and intuitive:

  • You get two-way data binding out of the box.

  • The syntax is close to vanilla HTML.

  • You can progressively enhance forms using SvelteKit’s form actions.

  • Both client-side and server-side validation are easy to implement.

Whether you’re building a simple contact form or a dynamic data-entry system, Svelte gives you the tools to do it cleanly and efficiently.

Reference: https://svelte.dev

Picture of Chau Nguyen Hoang

Chau Nguyen Hoang

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top