Basic Svelte
Introduction
Bindings
Advanced Svelte
Advanced reactivity
Motion
Advanced bindings
Advanced transitions
Context API
Special elements
<script module>
Next steps
Basic SvelteKit
Introduction
Routing
Loading data
Headers and cookies
Shared modules
API routes
Stores
Errors and redirects
Advanced SvelteKit
Page options
Link options
Advanced routing
Advanced loading
Environment variables
Conclusion
You can also add handlers that mutate data, such as POST
. In most cases, you should use form actions instead — you’ll end up writing less code, and it’ll work without JavaScript, making it more resilient.
Inside the keydown
event handler of the ‘add a todo’ <input>
, let’s post some data to the server:
<input
type="text"
autocomplete="off"
onkeydown={async (e) => {
if (e.key !== 'Enter') return;
const input = e.currentTarget;
const description = input.value;
const response = await fetch('/todo', {
method: 'POST',
body: JSON.stringify({ description }),
headers: {
'Content-Type': 'application/json'
}
});
input.value = '';
}}
/>
Here, we’re posting some JSON to the /todo
API route — using a userid
from the user’s cookies — and receiving the id
of the newly created todo in response.
Create the /todo
route by adding a src/routes/todo/+server.js
file with a POST
handler that calls createTodo
in src/lib/server/database.js
:
import { json } from '@sveltejs/kit';
import * as database from '$lib/server/database.js';
export async function POST({ request, cookies }) {
const { description } = await request.json();
const userid = cookies.get('userid');
const { id } = await database.createTodo({ userid, description });
return json({ id }, { status: 201 });
}
As with load
functions and form actions, the request
is a standard Request object; await request.json()
returns the data that we posted from the event handler.
We’re returning a response with a 201 Created status and the id
of the newly generated todo in our database. Back in the event handler, we can use this to update the page:
<input
type="text"
autocomplete="off"
onkeydown={async (e) => {
if (e.key !== 'Enter') return;
const input = e.currentTarget;
const description = input.value;
const response = await fetch('/todo', {
method: 'POST',
body: JSON.stringify({ description }),
headers: {
'Content-Type': 'application/json'
}
});
const { id } = await response.json();
data.todos = [...data.todos, {
id,
description
}];
input.value = '';
}}
/>
You should only mutate
data
in such a way that you’d get the same result by reloading the page.
<script>
let { data } = $props();
</script>
<div class="centered">
<h1>todos</h1>
<label>
add a todo:
<input
type="text"
autocomplete="off"
onkeydown={async (e) => {
if (e.key !== 'Enter') return;
const input = e.currentTarget;
const description = input.value;
// TODO handle submit
input.value = '';
}}
/>
</label>
<ul class="todos">
{#each data.todos as todo (todo.id)}
<li>
<label>
<input
type="checkbox"
checked={todo.done}
onchange={async (e) => {
const done = e.currentTarget.checked;
// TODO handle change
}}
/>
<span>{todo.description}</span>
<button
aria-label="Mark as complete"
onclick={async (e) => {
// TODO handle delete
}}
></button>
</label>
</li>
{/each}
</ul>
</div>
<style>
.centered {
max-width: 20em;
margin: 0 auto;
}
label {
display: flex;
width: 100%;
}
input[type="text"] {
flex: 1;
}
span {
flex: 1;
}
button {
border: none;
background: url(./remove.svg) no-repeat 50% 50%;
background-size: 1rem 1rem;
cursor: pointer;
height: 100%;
aspect-ratio: 1;
opacity: 0.5;
transition: opacity 0.2s;
}
button:hover {
opacity: 1;
}
</style>