These posts are aggregated from Svelte GitHub Repository.
This is probably the most common thing people need to do but I am still unsure especially with the new async stuff in the works.
I think a good example is selecting an item from a list, like a combobox.
Would this be the best approach:
<script type="ts">
let {id, selectedId = $bindable()} = $props()
const data = $derived(await fetchItems(id))
const transformedData = $derived(data.map(x => x.data))
const selectedItem = $derived(transformedData.find(x => x.id === selectedId))
// Or fetch from database
// const selectedItem = $derived(await fetchItem(selectedId))
function handleSelect(itemId) {
selectedId.value = itemId
}
</script>
Selected: <span>{selectedItem.name}</span>
{#each transformedData as item}
<div onclick={() => handleSelect(item.id)}>{item}</div>
{/each}
Before with {#await promise then x} blocks you could not access the result of promise in the code which was restrictive. There are many times you want to run a second async operation on the items of the first operation.
A website of the most common scenarios and the recommended approach.
The most common thing I do is data-fetching. But trying to figure out the best/recommended approach involves reading blog posts/github discussions/github issues/bun blog/reddit threads/youtube comments/etc. And it's always evolving too because of runes, async, etc.
I work mostly in vanilla Svelte. I feel like vanilla Svelte examples/guides are neglected a bit at the expense of SvelteKit.
I really like Bun's guides. They have a separate page on how to do the most common things. Nicely SEO'd too.
See: https://bun.com/docs/guides Example: https://bun.com/docs/guides/binary/arraybuffer-to-typedarray
It would be interesting to allow commenting on each example where people could debate the alternative/evolving approaches. This information is found inside Github issues at the moment.
The examples should be really small and focused. And cover a lot of real-world common variations. Like fetching data and then something else deriving from that fetched data.
I'm on the latest of Svelte and SvelteKit but if I use an $inspect() for example and I get the info (and the trace) in the browser's console and the link to the File.svelte to see the exact line where the variable changed then the line is totally wrong!
Why?
Hi everyone 👋
I'm trying to dynamically render Svelte to HTML at runtime, and I want to confirm if there's an official / sane way to do this.
I want to take the source code of a Svelte component as a string (not an already-imported module). That component can include imports of other local components. Then I want to:
I basically want: Svelte source code (text) → rendered HTML string.
This could run:
The one thing that keeps me in the React ecosystem is the first class support it has in an NX monorepo.
To be able to effortlessly setup multiple apps and libraries, scaffold components with their tests and stories for storybook etc...
Once Svelte 5 is out, It would be amazing if you could collaborate with the team at Nrwl to provide first class support for scaffolding sveltekit apps within an NX workspace, with generators to create routes, libs, e2e, stories, page.server.js etc
Basically to replicate what they have for React but for Sveltekit
Could such a thing be considered by the Svelte team?
I'm trying to wrap my head around how to have a nice decimal input field for my little svelte project. I think, I'm trapped in kind of a situation where I can achieve only two out of three requirements:
,1 to 0,10 and so on...Is there a way to achieve this or am I trying to do something too complicated?
I have tried:
But either I ran into some kind of infinite loops or things are overwriting each other...
I'd really appreciate if someone could hint me if this is possible and how to do this. Thank you very much!
I opened https://github.com/sveltejs/svelte/issues/17056.
They closed it. Ok.
Bu what is the idiomatic way of doing such a common thing on SPAs?
Can you help me understand better?
This is a long document; get yourself a cup of tea.
You can now use the await keyword in Svelte — in your <script>, inside $derived expressions, and in your markup — by installing the async branch...
npm i https://pkg.pr.new/svelte@async
...and adding the experimental.async option to your svelte.config.js (or wherever you configure Svelte):
// svelte.config.js
export default {
compilerOptions: {
experimental: {
async: true
}
},
kit: {
// ...
}
};
You can also try things out in the async playground.
You will find bugs! This is in no way production-ready. The PR that accompanies this discussion is at https://github.com/sveltejs/svelte/pull/15844.
In olden times, we did asynchronous work like fetching data inside onMount or an {#await ...} block. This works but it's quite verbose, and offers no coordination — if two components are both fetching stuff, then they will likely have independently managed error/loading states, often resulting in a janky UI with multiple spinners.
Frameworks like SvelteKit (or Remix or pre-App-Router Next.js, etc) offer an alternative: instead of fetching inside the component, we do our asynchronous work outside the component, for example in load functions. This typically results in better user experience (we can server-render the data, preload it, and coordinate everything) but it too has problems — prop-drilling, type shenanigans, coarse-grained invalidation, and logic that's hard to delete because it's often not obvious whether something in your load function is even being used.
In recent years component frameworks have explored a third way: putting asynchronous work back inside components, but in a way that is coordinated:
<Suspense>, startTransition, useTransition, use and React Server Components, that together allow you to manage async updatescreateResource API that can be used with <Suspense> and startTransition/useTransition for the same purposeawait inside a <script setup> in a component inside a <Suspense> boundary, though this experimental API only works for component creation, not subsequent updatesWe believe Svelte's compiler-centric nature offers us a way to have component-level async work with significantly better ergonomics and fewer drawbacks than existing approaches.
await keyword. Avoid framework-specific APIs and idioms to the extent possible<script>, inside $derived expressions, in the template, in attributes and component props, in control flow like {#if ...} blocks, or wherever else)await expressions need not result in sequential async work. Similarly, asynchronous work in two sibling components (for example) should happen simultaneouslyfoo changes, and await bar(foo) is (or will be) visible on the page, any occurrences of foo in the UI should not update until bar(foo) resolvesWe also want this to have minimal impact on performance and memory for existing codebases, and to cause little or no breakage for existing apps.
In a nutshell: you can now use await in three places that will today result in a syntax error:
<script>$derived expressionWe also introduce a pending snippet to <svelte:boundary>, which allows you to provide UI when await expressions inside the boundary are first resolving. For now, await expressions must be inside a boundary with a pending snippet (however deeply nested — for example you might have a single boundary at the very root of your app), though this constraint will likely be relaxed in future.
If state is read inside a $derived or template expression with an await, changes to that state will not be reflected in the UI until the expression resolves. For example in a situation like this...
<h1>Weather forecast for {city}</h1>
<p>{await getWeatherForecast(city)}</p>
...the <h1> will not update until the <p> does. (If getWeatherForecast were to fail, it would activate the nearest error boundary.)
To know if an update is currently pending, you can use $effect.pending():
{#if $effect.pending()}
<p>loading new data...</p>
{/if}
If unrelated state changes while an update is pending, it will be visible immediately (assuming it doesn't separately cause asynchronous updates).
The most obvious use case is loading data (which could be as simple as fetch, but in many cases will likely involve yet-to-be-designed utilities for client-server communication), but others include:
<img alt="..." src={await preload('...')}>)As much as framework authors like to witter on about rendering performance, the thing that really slows apps down is latency. In some cases you can reduce latency by speeding up your back end, or prefetching content you expect to need, or serving content from somewhere close to the user, but those things aren't always possible. What you can do is mitigate the effect of latency by minimising the number of round trips between the browser and the server.
Svelte helps by doing as much work as possible in parallel. For example here...
<li>apples {await getPrice('apple')} each</li>
<li>bananas {await getPrice('banana')} each</li>
<li>canteloupes {await getPrice('canteloupe')} each</li>
...the three calls to getPrice will happen simultaneously, even though they appear in sequence. Similarly, the three wise monkeys will do all their async work together:
<WiseMonkey verb="see" />
<WiseMonkey verb="hear" />
<WiseMonkey verb="speak" />
Not all work can be parallelized. Any await expressions inside the <script> run before expressions in the template, and in the sequence you would expect...
// `a` will be calculated and _then_ `b` will be calculated
let a = $derived(await foo(x));
let b = $derived(await bar(x));
...though note that if x subsequently updates, a and b will be recomputed in parallel. You can of course avoid the initial waterfall like so:
let aPromise = $derived(foo(x));
let bPromise = $derived(bar(x));
let a = $derived(await aPromise);
let b = $derived(await bPromise);
While unnecessary waterfalls can generally be prevented by pushing async work as far into the 'leaves' of your application as possible, there are also necessary waterfalls to contend with. For example, you can't use Promise.all here, because you need to know artist.id before you can call getTrackListing:
let artist = $derived(await search(query));
let tracks = $derived(await getTrackListing(artist.id));
It's better if you can do both fetches on the server, near your database. There are two ways to solve this: either anticipate the need for the track listing when you do the search...
let [artist, tracks] = $derived(await searchAndGetTrackListing(query));
...or use a mechanism like React Server Components, where the rendering happens on the server. Option 1 has less-than-ideal ergonomics, though it's basically equivalent to SvelteKit's load function. Option 2 is optimal from a waterfall prevention perspective, but we feel RSCs have significant trade-offs.
We anticipate that opinionated data-fetching patterns will emerge over time, along with new approaches inspired by RSCs, to solve this problem.
The work presented so far is the first step of a multi-stage process. While it's useful in its current form, more value will be unlocked with later stages:
Today, server-side rendering is fully synchronous. Because of this, if a <svelte:boundary> with a pending snippet is encountered during SSR, the pending snippet will be rendered.
It would be better to render the content instead, but this requires that SSR become an asynchronous operation.
In an ideal world we would also be able to stream the result where appropriate. This is complicated by the fact that you ideally need to know what's in the <head> before you get to the <body>. We have some ideas for how to design this sensibly, but it's not a current priority.
Once we get to this part, it's likely that the requirement for await expressions to be contained in a <svelte:boundary> will go away.
In SvelteKit we preload the code and data necessary for a navigation before it even occurs: when you hover over a link, or tap it, we import any modules needed by the route and begin running whichever load functions need to run. (This behaviour is configurable, of course.)
To make this work in a world where asynchronous work happens inside components, we need to be able to pretend that a state change occurred, and do the resulting updates 'off-screen'. The result can either be applied or discarded.
Colloquially, we've been describing this as a 'fork'. You could imagine several unresolved forks coexisting simultaneously until one reality is chosen (by the user clicking on one of several links they've been close to interacting with, for example). Most likely, we'll add an API to Svelte that allows frameworks like SvelteKit (but also particularly ambitious application authors) to enter the multiverse.
This all sounds very complicated, but in reality it's not all that different to how asynchronous updates already work. Nevertheless, it will take some finagling to get right, and in the interests of shipping we haven't included this work in the current PR.
Unless we want to create server endpoints for everything we want to fetch inside a component, we'll need tools for interacting with the server. Those tools will need to consider security, HTTP caching, mutations and invalidation, optimistic UI, batching, streaming, custom serialization, type safety and lots of other things.
We're at the early stages of figuring out what this all looks like, but we're very confident that the foundation we're laying here will allow us to design something really good.
Anticipating everyone's reaction: no, we're not going to suddenly make you rewrite all your SvelteKit apps. But taking all the other stuff together, a picture starts to emerge: a version of SvelteKit that's a thinner layer on top of Svelte. For example, as proud as we are of our zero-effort type safety, it's something you no longer need if you're fetching data directly inside your component.
Meanwhile the framework internals could potentially get simpler, because we'd be able to rely on common primitives inside Svelte itself. (Today, we can't reuse that much code between the server and client portions of SvelteKit, and we rely a lot on virtual modules and generated code. Some of that is for historical reasons, but some is necessary because anything asynchronous has to happen outside Svelte.)
It seems likely that a lot of interesting new possibilities will open up as a result of this work, and it seems at least plausible that we'll collectively find ourselves drifting away from primitives like load. Exactly what this would look like is to be determined, and it's something that we'll figure out together as a community.
startTransition/useTransitionIf you've used React or Solid's suspense implementation, you will have encountered startTransition and useTransition. These functions allows you to update state in such a way that the nearest suspense boundary doesn't show its fallback while waiting for any async work that is downstream of the state change.
In Svelte, we don't do this. Instead, state changes that result in asynchronous work always have their effects deferred until the asynchronous work is complete. While that work is ongoing, $effect.pending() is true. Any pending snippets are only shown when a boundary is first being created.
This does create the possibility that something distantly connected to a given piece of state has the power to delay (or prevent!) changes to that state from being reflected in the UI. We think this is preferable to the alternative (in which updates outside a useTransition or similar cause unwanted fallback UI to appear), though it may be necessary to develop techniques for identifying these chains.
In a case like this...
<p>{a} + {b} = {await fetch(`/add/${a}/${b}`).then((r) => r.json())}</p>
...it's possible to imagine a scenario in which a change to a is followed by a change to b while the first fetch is ongoing. If the second fetch somehow finishes first, we don't want the first fetch to be applied afterwards, since the resulting UI would show stale values.
As such, a given async expression must only resolve after its previous versions have also resolved.
Normally in Svelte, $derived expressions use 'push-pull' reactivity — they are invalidated when their dependencies change (the 'push') but are not re-evaluated until something reads them (the 'pull'). This doesn't work for async deriveds, because if we waited until the value was read the resulting promise would never resolve in time.
Instead, an 'async derived' is really just an effect and a source signal in a trenchcoat. We evalute the expression in the effect, and when the promise resolves, set the source value (unless the effect fired again in the interim).
For the most part, you don't need to think about this. There is one important implication though — while it's possible to create an 'unowned derived' (in other words, a derived that is not part of the 'effect tree', such as one created in an event handler) it is not possible to create an unowned async derived, because effects can only be created inside other effects. (Don't worry if you didn't follow this — it's inside baseball stuff, and describes an edge case you're unlikely to encounter. Svelte will tell you if you get this wrong.)
When a reaction (i.e. an effect or derived) runs, we track its dependencies by seeing which values are read during its execution. In pseudo-code:
let dependencies = null;
function get(source) {
dependencies?.add(source);
return source.value;
}
function update_reaction(reaction) {
dependencies = new Set();
reaction.fn();
reaction.dependencies = dependencies;
dependencies = null;
}
(This is simplified and wrong, but you get the idea.)
For asynchronous functions, this presents a challenge. To understand why, consider the order in which things happen here:
function a() {
console.log('a 1');
b();
console.log('a 2');
}
async function b() {
console.log('b 1');
await 0;
console.log('b 2');
}
a();
This will log a 1, b 1, a 2, b 2 — in other words despite the fact that b isn't even awaiting an asynchronous value, b 2 isn't logged until after it has returned to a.
In Svelte terms, this would mean that $derived(await a + b) or an equivalent {await a + b} template expression would register a dependency on a but not on b. But since we're a compiler we have a trick up our sleeves: we wrap the await expression in a function that restores the effect context, so that b is treated as a dependency.
On one level this is spooky compiler magic. But on another, it's just making the system work how a reasonable person would expect it to work. It does mean that if you extract the logic out into a function — {await a_plus_b()} — it will be treated differently, but during development Svelte will catch those cases and help you fix them.
$derived.byWhile you can do this...
let x = $derived.by(async () => await y);
...x will then be a Promise, not the value of await y. There's no sensible place to put the await that would result in x not being a Promise. (This is why it's pretty great that we're a compiler and can make the expression form the default, even though it makes other framework authors mad.)
If you have sufficiently complex logic that you need to use a function block, just declare the function and call it:
async function add(p1: Promise<number>, p2: Promise<number>) {
return await p1 + await p2;
}
let sum = $derived(await add(p1, p2));
Note the aforementioned caveat around context preservation — make sure you pass state into the function, rather than having the function close over the state it references, so that dependencies are correctly attached.
Normally, state does not update in the UI until everything that depends on it has finished resolving. This does not apply to a focused <input> element, which in many cases will be the source of the state change in question — instead, the rest of the UI 'catches up' to the input.
Because of how async reactivity works, there is one small and unavoidable breaking change: beforeUpdate and $effect.pre callbacks no longer run before control flow blocks are updated. If you're using those callbacks to set state that control flow logic depends on — which you absolutely shouldn't be — then you may experience breakage. As a result, we may have to wait until 6.0 for a non-experimental release of this stuff.
That was a lot; congratulations to those of you still here. I am sure you have questions, and that's a good thing. This is the place to ask them, or to offer feedback on the design. Let's go!
The Svelte team has been hard at work on asynchronous rendering, with client-side support and remote functions as our first two efforts. It’s time for the third: SSR.
There are three core pieces to the async problem:
The interplay between these creates a number of challenges for anyone seeking to create a seamless end-to-end experience.
When asynchronously rendering on the server, any await expressions not contained in a svelte:boundary with a pending snippet will block until their associated promise resolves. Await expressions behind a svelte:boundary with a pending snippet will not be reached — but more on that later. This means that if you write the following:
<div>{await delayed("Hey y'all!", 1000)</div>
The resulting HTML output will look like this:
<div>Hey y'all!</div>
…and if you had a boundary with a pending snippet:
<div>{await delayed("Hey y'all!", 1000)</div>
<svelte:boundary>
<div>{await delayed("What's up?", 1000)</div>
{#snippet pending()}
<div>Loading...</div>
{/snippet}
</svelte:boundary>
…the output would look like this:
<div>Hey y'all!</div>
<div>Loading...</div>
Because we have cool compiler superpowers, we can also optimize your code. The following would take one second to render, not two:
<div>{await delayed("Hey y'all!", 1000)</div>
<div>{await delayed("What's up?", 1000)</div>
You can use await everywhere — in component <script> blocks, in $derived expressions, in templates, and in normal modules and async functions.
When you render asynchronous content on the server, then send it to the client and hydrate it, one of two things will happen:
pending snippet on the server, the client will kick off the asynchronous work, replacing the pending snippet when the asynchronous work is donepending boundary), that content will be “normally” hydratedThe latter behavior might raise some eyebrows. What it means, practically, is that this:
<div>I slept for {await sleep(Math.random() * 1000)} milliseconds!</div>
Would output something like this on the server:
<div>I slept for 567 milliseconds!</div>
…and then, on the client during hydration, we’d wait for another random amount of time and you’d see it change to:
<div>I slept for 243 milliseconds!</div>
This really isn’t very desirable behavior. During hydration, you typically want to stick with the stuff you rendered on the server unless it actually needs to change! What we need to be able to do is render something asynchronously on the server, then hydrate it synchronously on the client based on what we rendered on the server. This requires serialization at some point. Somehow, we have to get the data you’ve rendered over the wire in such a way that we can retrieve it on the client and hydrate it into reactive JavaScript.
React solves this problem by making the serialization boundary be the client component. Data passed from a server component to a client component has to be serializable so that it can be sent over the wire and used in hydration. The downside of this approach is that React has to live in two worlds, where some of your components are server components (and therefore only run on the server) and some of them are client components (and therefore run on both the server, for initial renders, and the client for subsequent client-side ones). Svelte has always been a very isomorphic framework — we believe the Svelte code you write should be able to run equally well on the server and the client. Keeping to these roots, we think the more logical place to put this serialization boundary is at the resource level — at the actual place you’re fetching the data.
Thankfully, we’ve already taken care of this problem for you with remote functions in SvelteKit. Given a setup like this:
export const getUser = query(v.string(), (id) => getUserFromDatabase(id))
<script>
import { getUser } from './get-user.remote.js';
import { page } from '$app/state';
</script>
<h1>Hi, {(await getUser(page.params.userId).name}</h1>
…when server rendering, the result of getUser will be inlined into the resulting HTML, and during hydration, getUser will simply return the data synchronously — no delays or additional requests involved.
“But Elliott, I don’t want to use SvelteKit!” That’s fine! Remote functions have been our exploration into what the best possible version of data-fetching in SvelteKit could be. Now that we’ve had that exploration, we’re working on bringing some of that goodness into Svelte core, so that other framework authors can build similar solutions, or you can make your own.
pending snippets?The above behavior could be kind of annoying! It means that you have to send your server-rendered content to the browser, then kick off whatever asynchronous work needs to happen to render the non-pending contents of your boundary. We plan to fix this with streaming. In the future, this:
<div>{await delayed("Hey y'all!", 1000)</div>
<svelte:boundary>
<div>{await delayed("What's up?", 1000)</div>
{#snippet pending()}
<div>Loading...</div>
{/snippet}
</svelte:boundary>
will immediately render the pending snippet, but start rendering the non-pending content in the background. This non-pending content can then be sent to the browser after the initial response. This is the best of both worlds, where you can de-prioritize nonessential content by rendering a skeleton without needing multiple server round trips to fully hydrate your application.
It’s out in the latest version of svelte! Just set experimental.async: true in your Svelte compile options. Once you’ve done this, awaiting or calling .then on the result of render will render your component asynchronously. If you’re using a framework, that framework will have to implement support. In the very near future, we’ll release an update to SvelteKit to pick up your compileOptions and automatically use async server rendering if you’ve turned the experimental compile option on.