React
-
SvelteKit Forms: Back to Basics (And Why That's a Good Thing)
Before we talk about SvelteKit, we should touch on how React form handling works. I’m writing this to remind myself of the
modernway to do it…- You set up
useStatefor every input field - Write
onChangehandlers to update state on every keystroke - Add an
onSubmithandler to prevent the browser’s default behavior, construct a JSON payload, fire off afetchrequest - Manage loading state to disable the submit button
- Manually parse the response to show success or error messages.
That’s a lot jumps to be hooped.
Frameworks like Next.js have improved this with server actions, but the fundamental approach remains the same: a cage match with the browsers native form handling.
SvelteKit takes a completely different approach. It just uses regular HTML.
How SvelteKit Forms Work
In SvelteKit, you write a standard
<form method="POST">in your+page.sveltefile. That’s your UI. Then, in a+page.server.tsfile in the same directory, you export anactionsobject that handles the submission.The server-side action receives a request object, extracts the form data, runs your logic, and returns either a
redirector afailwith validation errors. No client-side state management, no manual fetch calls, no JSON serialization.// +page.server.ts export const actions = { default: async ({ request }) => { const data = await request.formData(); const email = data.get('email'); const password = data.get('password'); if (!email) { return fail(400, { email, missing: true }); } // authenticate user... throw redirect(303, '/dashboard'); } };If you’re a backend developer coming from Python or Ruby, this should feel familiar. The browser collects the data, posts it to a URL, and the server processes it. Stateless, reliable, and native.
Progressive Enhancement: The Best of Both Worlds
You might be thinking, “Okay, but I don’t want full page reloads every time someone submits a form.” Fair point. SvelteKit handles this with something called progressive enhancement. You add
use:enhanceto your form tag:<form method="POST" use:enhance> <!-- your inputs --> </form>That single directive tells SvelteKit to automatically intercept the submission, prevent the page reload, submit the data via fetch under the hood, and update the
formprop with any validation errors returned from the server.But wait there’s more.
If JavaScript fails to load or the user is on a terrible connection, the form still works. It falls back to the browser’s native POST request.
Your form doesn’t break just because a script didn’t load. That’s how the web is supposed to work.
The React approach treats the browser as a rendering target and reimplements everything in JavaScript. SvelteKit treats the browser as a platform and builds on top of what’s already there.
Now, don’t get me wrong. I’ll write React code any day of the week at the ole w2, but I am really liking how Svelte and SvelteKit has decided to approach these sorts of features.
- You set up
-
Svelte 5 Runes: A React Developer's Guide to Reactivity
Continuing my series on Svelte topics, today we’re talking about runes. If you’re coming from React, this is is going to be a different way to work with reactivity in modern JavaScript.
These blog posts might be what is considered the basics, but it helps me learn and think through the topics if I work on blog posts around the important things that every developer needs to know.
What Are Runes?
In Svelte 5, runes are special symbols that start with the dollar sign (
$). They look like regular JavaScript functions, but they’re actually compiler directives, reserved keywords that tell the Svelte compiler how to wire up reactivity during the build step.If you’ve used decorators in Python or macros in other languages, runes fill a similar role. They look like standard JavaScript, but the compiler transforms them into something more powerful behind the scenes.
Let’s walk through the four runes you’ll use most.
$state— The Engine of Reactivity$stateis the foundation. It declares reactive state in your component.<script> let count = $state(0); </script> <button onclick={() => count++}>{count}</button>In React,
useStatereturns an immutable value and a setter function, so you always need thatsetCountcall. In Svelte,$statereturns a deeply reactive proxy. You just mutate the value directly, and the compiler handles the rest. No setter function, no spread operators for nested objects. It just works.$derived— Computed Values Without Dependency ArraysIn React, you’d reach for
useMemohere, and you’d need to explicitly declare a dependency array so React knows when to recalculate.<script> let count = $state(0); let doubled = $derived(count * 2); </script>Dependency arrays are prone to human error. We forget what depends on what, and that leads to stale data or unnecessary recalculations.
$derivedautomatically tracks whatever state variables are used inside of it. No dependency array needed. It just reads what it reads, and recalculates when those values change.$effect— Side Effects That Actually Make SenseThis is the equivalent of
useEffectin React, which is notoriously tricky. Missing dependencies, stale closures, infinite loops… all the big gotchas are in useEffect calls.In Svelte,
$effectis used to synchronize state with external systems, like writing to local storage or updating a canvas:<script> let theme = $state('dark'); $effect(() => { localStorage.setItem('theme', theme); }); </script>Just like
$derived, it automatically tracks its dependencies and only runs when the state it reads actually changes. No dependency array, no cleanup function gotchas. It runs when it needs to run. That’s it.$props— Clean Component InterfacesEvery framework needs a way to pass data into components. In Svelte 5,
$propsmakes this look like standard JavaScript object destructuring:<script> let { name, age, role = 'viewer' } = $props(); </script> <p>{name} ({age}) - {role}</p>Default values, rest parameters, renaming … it all works exactly how you’d expect from CommonJS. If you know destructuring, you already know
$props. It’s readable, predictable, and there’s nothing new to learn.Runes Me Over
You’ve probably noticed a theme. Svelte 5 runes eliminate a whole class of bugs that come from manually managing dependencies. React makes you think about when things should update. Svelte’s goal is to figure it out for you at compile time.
/ Web-development / javascript / svelte / React
-
Svelte vs React: State Management Without the Ceremony
Continuing my Svelte deep-dive series, let’s talk about state management and reactivity. This is where the differences between React and Svelte can ‘feel’ much different.
React’s State Ceremony
In React, state requires a specific ritual. You declare state with
useState, which gives you a getter and a setter:const [count, setCount] = useState(0); function increment() { setCount(count + 1); }Want to update a variable? You have to call a function. You can’t just reassign
count. React won’t know anything changed. This is fine once you internalize it, but it adds ceremony to what should be a simple operation.Then there’s
useEffect, which is where things get tricky. You need to understand dependency arrays, and if you get them wrong, you’re looking at infinite loops or stale data:useEffect(() => { document.title = `Count: ${count}`; }, [count]); // forget this array and enjoy your infinite loopSome of
useEffectusage is actually unnecessary and likely using it wrong. If you’re using it for data transformations, derived values from state or props, or responding to user events, you’re probably reaching for the wrong tool.The React docs themselves will tell you that you might not need an effect. It’s a common source of bugs and confusion, especially for developers who are still building their mental model of React’s render cycle.
Svelte: Reactivity Through the Language Itself
Svelte takes a fundamentally different approach. Reactivity is baked into the language semantics. Want to declare state? Just declare a variable:
<script> let count = $state(0); function increment() { count += 1; } </script> <button onclick={increment}>{count}</button>That’s it. You assign a new value, and the DOM updates. The Svelte compiler sees your assignments and automatically generates the code to update exactly the parts of the DOM that depend on that variable. No virtual DOM diffing, no setter functions, no dependency arrays to manage.
Need a derived value? Svelte has you covered with
$derived:<script> let count = $state(0); let doubled = $derived(count * 2); </script> <p>{count} doubled is {doubled}</p>In React, you’d either compute this inline, use
useMemowith a dependency array, or… if you didn’t know better reach foruseEffectand a second piece of state (please don’t do this).Svelte’s
$effectrune exists for side effects like updatingdocument.titleor logging, but you should reach for it far less often thanuseEffectin React. The compiler handles most of whatuseEffectgets used for automatically.More Svelte comparisons coming as I keep digging in. Thanks for Svelting with me.
/ javascript / svelte / React / Web development
-
Svelte vs React: The Virtual DOM Tax You Might Not Need
I’m diving more into Svelte and SvelteKit lately, and I’m going to be writing a few posts about it as I learn. Fair warning: some of these will be general knowledge posts, but writing things out helps me internalize the details.
The Virtual DOM Question
It’s well known that React relies on a virtual DOM. The basic idea is that React maintains a copy of the DOM in memory, diffs it against the actual DOM, and then batches the changes to update the real thing. This works, but having to maintain this virtual DOM can lead to complications and confusion around what triggers a render or a re-render. If you’ve ever stared at a
useEffectdependency array wondering why your component is re-rendering, you know what I mean.Svelte takes a completely different approach. It’s not a library you ship to the browser, it’s a compiler step. You write Svelte code, and it compiles down to highly optimized vanilla JavaScript that surgically updates the DOM directly. No virtual DOM to maintain. No diffing algorithm running in the background. The framework essentially disappears at build time, and what you’re left with is just… JavaScript.
Templating That Feels Like the Web
I like how Svelte handles the relationship between HTML, CSS, and JavaScript. React forces you to write HTML inside JavaScript using JSX. You get used to it, sure, but it’s a specific way of thinking about your UI that can take some getting used to.
Svelte flips this around. Your
.sveltefiles are structured more like traditional web pages — you’ve got<script>tags for your JavaScript, regular HTML for markup, and<style>tags for CSS. Everything lives in one file, but there’s a clear separation between the three concerns.If you’ve ever worked with Django templates, Laravel Blade, or Ruby on Rails views, this will feel immediately familiar. It’s a lot closer to how the web actually works than JSX’s “everything is JavaScript” approach. For someone coming from those backgrounds, the learning curve is noticeably gentler.
More Svelte posts coming as I dig deeper. That’s all for now!
/ javascript / svelte / React / Web development