{
  "version": "https://jsonfeed.org/version/1",
  "title": "Forms on LLBBL Blog",
  "icon": "https://avatars.micro.blog/avatars/2023/40/125738.jpg",
  "home_page_url": "https://llbbl.blog/",
  "feed_url": "https://llbbl.blog/feed.json",
  "items": [
      {
        "id": "http://llbbl.micro.blog/2026/04/11/sveltekit-forms-back-to-basics.html",
        "title": "SvelteKit Forms: Back to Basics (And Why That's a Good Thing)",
        "content_html": "<p>Before we talk about SvelteKit, we should touch on how React form handling works. I&rsquo;m writing this to remind myself of the <code>modern</code> way to do it&hellip;</p>\n<ul>\n<li>You set up <code>useState</code> for every input field</li>\n<li>Write <code>onChange</code> handlers to update state on every keystroke</li>\n<li>Add an <code>onSubmit</code> handler to prevent the browser&rsquo;s default behavior, construct a JSON payload, fire off a <code>fetch</code> request</li>\n<li>Manage loading state to disable the submit button</li>\n<li>Manually parse the response to show success or error messages.</li>\n</ul>\n<p>That&rsquo;s a lot jumps to be hooped.</p>\n<p>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.</p>\n<p>SvelteKit takes a completely different approach. It just uses regular HTML.</p>\n<h2 id=\"how-sveltekit-forms-work\">How SvelteKit Forms Work</h2>\n<p>In SvelteKit, you write a standard <code>&lt;form method=&quot;POST&quot;&gt;</code> in your <code>+page.svelte</code> file. That&rsquo;s your UI. Then, in a <code>+page.server.ts</code> file in the same directory, you export an <code>actions</code> object that handles the submission.</p>\n<p>The server-side action receives a request object, extracts the form data, runs your logic, and returns either a <code>redirect</code> or a <code>fail</code> with validation errors. No client-side state management, no manual fetch calls, no JSON serialization.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-typescript\" data-lang=\"typescript\"><span style=\"color:#75715e\">// +page.server.ts\n</span><span style=\"color:#75715e\"></span><span style=\"color:#66d9ef\">export</span> <span style=\"color:#66d9ef\">const</span> <span style=\"color:#a6e22e\">actions</span> <span style=\"color:#f92672\">=</span> {\n  <span style=\"color:#66d9ef\">default</span><span style=\"color:#f92672\">:</span> <span style=\"color:#66d9ef\">async</span> ({ <span style=\"color:#a6e22e\">request</span> }) <span style=\"color:#f92672\">=&gt;</span> {\n    <span style=\"color:#66d9ef\">const</span> <span style=\"color:#a6e22e\">data</span> <span style=\"color:#f92672\">=</span> <span style=\"color:#66d9ef\">await</span> <span style=\"color:#a6e22e\">request</span>.<span style=\"color:#a6e22e\">formData</span>();\n    <span style=\"color:#66d9ef\">const</span> <span style=\"color:#a6e22e\">email</span> <span style=\"color:#f92672\">=</span> <span style=\"color:#a6e22e\">data</span>.<span style=\"color:#66d9ef\">get</span>(<span style=\"color:#e6db74\">&#39;email&#39;</span>);\n    <span style=\"color:#66d9ef\">const</span> <span style=\"color:#a6e22e\">password</span> <span style=\"color:#f92672\">=</span> <span style=\"color:#a6e22e\">data</span>.<span style=\"color:#66d9ef\">get</span>(<span style=\"color:#e6db74\">&#39;password&#39;</span>);\n\n    <span style=\"color:#66d9ef\">if</span> (<span style=\"color:#f92672\">!</span><span style=\"color:#a6e22e\">email</span>) {\n      <span style=\"color:#66d9ef\">return</span> <span style=\"color:#a6e22e\">fail</span>(<span style=\"color:#ae81ff\">400</span>, { <span style=\"color:#a6e22e\">email</span>, <span style=\"color:#a6e22e\">missing</span>: <span style=\"color:#66d9ef\">true</span> });\n    }\n\n    <span style=\"color:#75715e\">// authenticate user...\n</span><span style=\"color:#75715e\"></span>    <span style=\"color:#66d9ef\">throw</span> <span style=\"color:#a6e22e\">redirect</span>(<span style=\"color:#ae81ff\">303</span>, <span style=\"color:#e6db74\">&#39;/dashboard&#39;</span>);\n  }\n};\n</code></pre></div><p>If you&rsquo;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.</p>\n<h2 id=\"progressive-enhancement-the-best-of-both-worlds\">Progressive Enhancement: The Best of Both Worlds</h2>\n<p>You might be thinking, &ldquo;Okay, but I don&rsquo;t want full page reloads every time someone submits a form.&rdquo; Fair point. SvelteKit handles this with something called progressive enhancement. You add <code>use:enhance</code> to your form tag:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-svelte\" data-lang=\"svelte\">&lt;<span style=\"color:#f92672\">form</span> <span style=\"color:#a6e22e\">method</span><span style=\"color:#f92672\">=</span><span style=\"color:#e6db74\">&#34;POST&#34;</span> <span style=\"color:#a6e22e\">use:enhance</span>&gt;\n  <span style=\"color:#75715e\">&lt;!-- your inputs --&gt;</span>\n&lt;/<span style=\"color:#f92672\">form</span>&gt;\n</code></pre></div><p>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 <code>form</code> prop with any validation errors returned from the server.</p>\n<p>But wait there&rsquo;s more.</p>\n<p>If JavaScript fails to load or the user is on a terrible connection, the form still works. It falls back to the browser&rsquo;s native POST request.</p>\n<p>Your form doesn&rsquo;t break just because a script didn&rsquo;t load. That&rsquo;s how the web is supposed to work.</p>\n<p>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&rsquo;s already there.</p>\n<p>Now, don&rsquo;t get me wrong. I&rsquo;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.</p>\n",
        "date_published": "2026-04-11T10:00:00-05:00",
        "url": "https://llbbl.blog/2026/04/11/sveltekit-forms-back-to-basics.html",
        "tags": ["Webdev","svelte","React","Sveltekit","Forms"]
      }
  ]
}
