In the previous lessons, you learned how to use Svelte’s reactivity system to manage dynamic data, such as timers and URLs, using $effect
and reactive built-ins like SvelteDate
and SvelteURL
. Now, we’ll shift our focus to a common real-world use case: managing form state. Forms are a fundamental part of web applications, and handling their state effectively is crucial for creating smooth user experiences.
In this lesson, you’ll learn how to use the $state
rune to manage form data reactively. By the end, you’ll be able to build a form that updates its state in real time and handles submissions gracefully. This builds on the reactivity concepts you’ve already learned, applying them to a practical scenario.
Let’s dive in!
To manage form state in Svelte, we’ll use the $state
rune to create a reactive object that holds the form’s data. This object will automatically update whenever the user interacts with the form, ensuring the UI stays in sync with the input values.
Here’s how to define a reactive state object for a form:
svelte1<script>
2 let formData = $state({
3 firstName: '',
4 lastName: '',
5 email: '',
6 age: '',
7 gender: 'male', // Default selection for radio buttons
8 subscribe: false // Default selection for checkbox
9 });
10</script>
In this example, formData
is a reactive object that contains fields for firstName
, lastName
, email
, age
, gender
, and subscribe
. The $state
rune ensures that any changes to these fields are automatically reflected in the UI.
Next, we’ll bind the form inputs to this state object using Svelte’s bind:value
, bind:group
, and bind:checked
directives. Here’s how to bind a text input for the firstName
field:
svelte1<label> 2 First Name: 3 <input type="text" bind:value={formData.firstName} required /> 4</label>
Similarly, we can bind radio buttons to the gender
field and a checkbox to the subscribe
field:
svelte1<fieldset> 2 <legend>Gender:</legend> 3 <label> 4 <input type="radio" value="male" bind:group={formData.gender} /> Male 5 </label> 6 <label> 7 <input type="radio" value="female" bind:group={formData.gender} /> Female 8 </label> 9 <label> 10 <input type="radio" value="other" bind:group={formData.gender} /> Other 11 </label> 12</fieldset> 13 14<label> 15 <input type="checkbox" bind:checked={formData.subscribe} /> Subscribe to Newsletter 16</label>
By binding the form inputs to the formData
object, any changes the user makes will automatically update the state, and vice versa.
Once the form is set up, the next step is to handle its submission. In Svelte, you can use the onsubmit
event to trigger a function when the form is submitted. This function can prevent the default form behavior (which would reload the page) and process the form data instead.
Here’s how to handle form submission:
svelte1<script> 2 function handleSubmit(event) { 3 event.preventDefault(); // Prevent default form submission 4 alert(`Form Data:\n 5 First Name: ${formData.firstName}\n 6 Last Name: ${formData.lastName}\n 7 Email: ${formData.email}\n 8 Age: ${formData.age}\n 9 Gender: ${formData.gender}\n 10 Subscribe to Newsletter: ${formData.subscribe ? 'Yes' : 'No'} 11 `); 12 } 13</script> 14 15<form onsubmit={handleSubmit}> 16 <!-- Form inputs go here --> 17 <button type="submit">Submit</button> 18</form>
In this example, the handleSubmit
function prevents the default form behavior using event.preventDefault()
and displays the form data in an alert. This is a simple way to verify that the form data is being captured correctly.
To make the form even more interactive, you can display a real-time preview of the form data:
svelte1<h3>Form Preview:</h3> 2<p>First Name: {formData.firstName}</p> 3<p>Last Name: {formData.lastName}</p> 4<p>Email: {formData.email}</p> 5<p>Age: {formData.age}</p> 6<p>Gender: {formData.gender}</p> 7<p>Subscribe to Newsletter: {formData.subscribe ? 'Yes' : 'No'}</p>
This preview updates automatically as the user fills out the form, thanks to Svelte’s reactivity.
svelte1<script> 2 // Define a reactive state object to manage form data 3 let formData = $state({ 4 firstName: '', 5 lastName: '', 6 email: '', 7 age: '', 8 gender: 'male', // Default selection for radio buttons 9 subscribe: false // Default selection for checkbox 10 }); 11 12 // Function to handle form submission 13 function handleSubmit(event) { 14 event.preventDefault(); // Prevent default form submission 15 alert(`Form Data:\n 16 First Name: ${formData.firstName}\n 17 Last Name: ${formData.lastName}\n 18 Email: ${formData.email}\n 19 Age: ${formData.age}\n 20 Gender: ${formData.gender}\n 21 Subscribe to Newsletter: ${formData.subscribe ? 'Yes' : 'No'} 22 `); 23 } 24</script> 25 26<form onsubmit={handleSubmit}> 27 <label> 28 First Name: 29 <input type="text" bind:value={formData.firstName} required /> 30 </label> 31 <br /> 32 33 <label> 34 Last Name: 35 <input type="text" bind:value={formData.lastName} required /> 36 </label> 37 <br /> 38 39 <label> 40 Email: 41 <input type="email" bind:value={formData.email} required /> 42 </label> 43 <br /> 44 45 <label> 46 Age: 47 <input type="number" bind:value={formData.age} min="0" /> 48 </label> 49 <br /> 50 51 <fieldset> 52 <legend>Gender:</legend> 53 <label> 54 <input type="radio" value="male" bind:group={formData.gender} /> Male 55 </label> 56 <label> 57 <input type="radio" value="female" bind:group={formData.gender} /> Female 58 </label> 59 <label> 60 <input type="radio" value="other" bind:group={formData.gender} /> Other 61 </label> 62 </fieldset> 63 <br /> 64 65 <label> 66 <input type="checkbox" bind:checked={formData.subscribe} /> Subscribe to Newsletter 67 </label> 68 <br /> 69 70 <button type="submit">Submit</button> 71</form> 72 73<!-- Display selected values --> 74<h3>Form Preview:</h3> 75<p>First Name: {formData.firstName}</p> 76<p>Last Name: {formData.lastName}</p> 77<p>Email: {formData.email}</p> 78<p>Age: {formData.age}</p> 79<p>Gender: {formData.gender}</p> 80<p>Subscribe to Newsletter: {formData.subscribe ? 'Yes' : 'No'}</p>
In this lesson, you learned how to manage form state in Svelte using the $state
rune. Here are some best practices to keep in mind:
- Organize Form State: Use a single reactive object to manage all form fields. This keeps your code clean and makes it easier to track changes.
- Use Binding Directives: Leverage
bind:value
,bind:group
, andbind:checked
to connect form inputs to your state object. - Handle Submissions Gracefully: Use
event.preventDefault()
to prevent page reloads and process form data programmatically.
In the practice exercises, you’ll:
- Build a reactive form with multiple input types.
- Handle form submissions and display the data.
- Experiment with real-time form previews.
Take your time to explore and experiment with the code. Managing form state effectively is a key skill in building dynamic and user-friendly web applications. Great job, and keep up the good work!