Updates

These posts are aggregated from Svelte GitHub Repository.

  • Svelte Philosophy

    This is an attempt to articulate the Svelte philosophy — our bedrock principles, that guide our design decisions.
  • Render snippet without the @render tag

    Hello, first I'll explain my aim because the solution I am after might not be the best one.

    Basically I have a classic set of components for integrating with MapBox. I have a Map component and MapMarker components that I put inside the Map. Then my markers would need a popup when I click on them. The good thing is that what is inside the popup is entirely based on a component I already have because it is used somewhere else on the website.

    Therefore my gut feeling was that it would be ideal to put the content of my popup in the snippet of the MapMarker. In other cases, I would have been able to use the snippet easily because it is in the children prop. However in this case, I have to pass the HTML to a javascript function setHTML, and I have no idea how to use the children prop in this scenario. In the component it uses the @render tag. I have tried to just use the children as a function but I get an error saying it cannot be called outside of the @render tag.

    I kind of can understand why. At the end of the day, the children is not just some piece of simple html, otherwise it would be rendered with @html instead. There is reactivity and all, and I might loose the scoped CSS, I get that. For my use case, having to re-inject the style in a way or another and have html created at mount time would be acceptable. If anybody has an idea of how I could achieve this, I'd love to hear about it.

    Thank you in advance !

  • Automated accessibility testing for SvelteKit apps

    Quick accessibility testing for SvelteKit projects

    Sharing a tool I built for automated WCAG 2.1 testing that works well with SvelteKit apps.

    Terminal scan (no install)

    npx accessscore https://your-sveltekit-app.com
    

    Runs 16 WCAG 2.1 Level A/AA checks and outputs your score, grade, and issues.

    Results for framework sites

    Site Score Grade Issues
    svelte.dev 87 B 10
    nextjs.org 100 A 1
    react.dev 82 B 14
    tailwindcss.com 73 C 48

    svelte.dev scores 87/B — solid but there's room for improvement (missing skip nav, heading hierarchy, some link text issues).

    Common SvelteKit a11y fixes

    Document language (in app.html):

    <html lang="en">
    

    Skip navigation (in +layout.svelte):

    <a href="#main" class="sr-only focus:not-sr-only">Skip to content</a>
    <nav>...</nav>
    <main id="main"><slot /></main>
    

    Image alt text:

    <img src={product.image} alt={product.name} />
    

    Form labels:

    <label for="email">Email</label>
    <input id="email" type="email" bind:value={email} />
    

    Svelte already has built-in a11y warnings in the compiler (which is great!), but automated runtime scanning catches issues that static analysis misses — like missing alt text in dynamically rendered content.

    Full tool: accessscore.autonomous-claude.com

  • Svelte Advanced Component+Snippet Proposal

    Svelte Advanced Component+Snippet Proposal

    This proposal outlines behavior and syntax for a combination of Components and Snippets in Svelte.

    <script lang="ts">
        let snipA: Snippet = () => snippet()
        let snipB: Snippet = () => snippetArgs(1, 2, 3)
        let snipC: Snippet = () => Component()
        let snipD: Snippet = () => ComponentArgs({ a: 1, b: 2, c: 3})
    </script>
    

    TL;DR

    • Snippets are great, but have are not flexible/powerful enough.
    • The exising workarounds suck.
    • Snippets and Components are not interchangable, but should be.
    • Composability of Snippets/Components in Svelte is limited.

    Motivation

    Until now, Components have been the "backbone" of Svelte. Usually, nothing works without them. Snippets add more flexibility and replace the old slots.

    Snippets are great. They allow for a kind of composability, mainly the ability to pass "snippets" of UI to another Component. It also works great for sharing code for UI-parts that are "not worth creating a component file".

    This works great with Snippets
    <script lang="ts">
        import LeftRight from "./LeftRight.svelte"
    </script>
    
    <LeftRight>
        {#snippet left()}
            <p>Left</p>
        {/snippet}
        {#snippet right()}
            <p>Right</p>
        {/snippet}
    </LeftRight>
    
    Sharing Code by exporting a Snippet
    <script lang="ts" module>
        export { smallPart }
    </script>
    
    {#snippet smallPart()}
        <p>Small Part</p>
    {/snippet}
    

    This is great for the end-user and also for library authors that implement a View/Component that should show some arbitrary UI in some place within. This only works "flawlessly" inside the template. When using Snippets in (JS) code, then there are severe limitations!

    Works great in Template
    <script lang="ts">
        import Container from "./Container.svelte"
    
        const a = 1
        const b = 2
    </script>
    
    <Container>
        {#snippet children()}
            <p>a = {a}</p>
            <p>b = {b}</p>
        {/snippet}
    </Container>
    
    Limitations in Code
    <script lang="ts">
        import ModalStack from "./ModalStack.svelte"
    
        let modalStack: ModalStack
    
        // a snippet where everyting is populated inside the template works
        modalStack.pushModal(specificModalContent)
    
        // ❌ not possible to populate a snippet within code
        modalStack.pushModal(genericWarning("Some runtime reson"))
        modalStack.pushModal(() => genericWarning("Some runtime reson"))
    </script>
    
    <ModalStack bind:this={modalStack} />
    
    {#snippet specificModalContent()}
        <p class="text-xl text-red">RAM Outtage Warning</p>
    {/snippet}
    
    {#snippet genericWarning(text: string)}
        <p class="text-xl text-orange">{text}</p>
    {/snippet}
    

    Authors can work around this, in places they accept a Snippet, by accepting not only a Snippet, but also its props/arguments. But this is not only cumbersome, but also hard to set TypeScript types correctly.

    Possible Workaround
    <script lang="ts">
        import ModalStack from "./ModalStack.svelte"
    
        let modalStack: ModalStack
    
        // pushModal<T>(snippet: Snippet<T>, arguments: T) { ... }
        modalStack.pushModal(genericWarning, ["Some runtime reson"])
    </script>
    
    <ModalStack bind:this={modalStack} />
    
    {#snippet genericWarning(text: string)}
        <p class="text-xl text-orange">{text}</p>
    {/snippet}
    

    This was first discussed in #10678.

    This solves our problem, but now makes using Snippets without arguments worse.

    But there is another problem: When you want to use a Component in a place only Snippets are allowed in, you have to use redirection.

    Using Components as a Snippet
    <script lang="ts">
        import ModalStack from "./ModalStack.svelte"
        import ComponentModal from "./ComponentModal.svelte"
    
        let modalStack: ModalStack
    
        // ❌ does not work
        modalStack.pushModal(ComponentModal)
    
        // we can work around this too, by "redirecting" to the populated snippet defined below
        modalStack.pushModal(snippetComponentModal)
    </script>
    
    <ModalStack bind:this={modalStack} />
    
    {#snippet snippetComponentModal()}
        <ComponentModal />
    {/snippet}
    

    But now imagine if this Component had props! Just like Snippets can have props/arguments.

    The Problem I See

    As a library author I would like to support all "kinds of UI" a user wants to give to me.

    The user should be able to provide any view they choose:

    modalStack.pushModal(snippetWithoutArguments);
    modalStack.pushModal(snippetWithArguments, [arg0, arg1, arg2]);
    modalStack.pushModal(ComponentWithoutProps);
    modalStack.pushModal(ComponentWithoutProps, { arg0, arg1, arg2 });
    

    Internallsyyou have to treat a "Modal" similar to this:

    type Modal<T> =
        | { snippet: Snippet }
        | { snippet: Snippet<T>; arguments: T }
        | { component: Component }
        | { component: Component<T>; props: T };
    

    Why do we have to do this? Because to render it, you have to know what it is:

    Rendering such a Modal
    <script lang="ts">
        let {
            modal
        }: {
            modal: Modal<unknown>
        } = $props()
    </script>
    
    {#if "component" in modal && "props" in modal}
        <modal.component {...modal.props} />
    {:else if "component" in modal}
        <modal.component />
    {:else if "snippet" in modal && "arguments" in modal}
        {@render modal.snippet(...modal.arguments)}
        <!-- For the record: The above isn't even possible, because you cannot spread an array into a Snippet -->
        <!-- Therefore you'd have to have it be `Snippet<[T]>`, and you can only pass _one_ value -->
    {:else if "snippet" in modal}
        {@render modal.snippet()}
    {/if}
    

    Some of the problem with the above are:

    • This is unsustainable especially when it comes to typing
    • The logic of what to render should be passed by the user, and not be managed by a library
    • This code should ideally not even be able to access arguments/props! They should be isolated from this code.

    Why this is a Problem

    Think about this, you want to render a list of Snippets inside buttons and highlight the last one clicked on:

    <script lang="ts">
        // first argument represents "isSelected"
        let snippets: Snippet<[boolean]>[] = $state([])
        let selectedIndex: number | null = $state(null)
    </script>
    
    {#each snippets as snippet, i}
        {@render snippet(i === selectedIndex)}
    {/each}
    

    Now a user of this code wants to add a Snippet, this case works fine:

    <script lang="ts">
        snippets.push(specificIcon)
    </script>
    
    {#snippet specificIcon(selected: boolean)}
        <Icon icon={gears} color={selected ? "blue" : "neutral"} />
    {/snippet}
    

    But this turns into a bad DX really fast:

    <script lang="ts">
        import { type IconType, gear, house } from "./icons"
    
        // we have to "redirect" to the "populated" snippets defined below
        snippets.push(gearIcon)
        snippets.push(houseIcon)
    </script>
    
    {#snippet genericIcon(icon: IconType, selected: boolean)}
        <Icon {icon} color={selected ? "blue" : "neutral"} />
    {/snippet}
    
    {#snippet gearIcon(selected: boolean)}
        {@render genericIcon(gear, selected)}
    {/snippet}
    {#snippet houseIcon(selected: boolean)}
        {@render genericIcon(house, selected)}
    {/snippet}
    

    Because you can not fix/set/populate Snippet arguments (neither by parts, or all), you have to defined snippets for each entry seperately below.

    How this could/should look

    <script lang="ts">
        import { type IconType, gear, house } from "./icons"
    
        // this converts the `Snippet<[boolean, IconType]>` into `Snippet<[boolean]>`, prepopulating the icon
        snippets.push((selected) => genericIcon(gear, selected))
        snippets.push((selected) => genericIcon(house, selected))
    </script>
    
    {#snippet genericIcon(icon: IconType, selected: boolean)}
        <Icon {icon} color={selected ? "blue" : "neutral"} />
    {/snippet}
    

    Having the ability to populate/bind Snippet arguments, while also keeping others free to "pass on" greatly improves Composability.

    Composability is a design principle where complex systems are built from independent, interchangeable components (like LEGOs) that can be easily assembled, rearranged, or replaced to create new functions or adapt to changes, offering flexibility, reuse, and agility, especially in software, IT, and business architecture. It allows building specialized solutions by combining existing blocks, reducing development from scratch and enabling quicker responses to new needs.

    Let's go even further

    But I don't think we should stop there.

    When a user defined the above genericIcon not as a Snippet, but as a Component, then they would have to "redirect using a Snippet" again!

    They should not be punished for using a Component if they prefer that. Therefore the below code should be available to them too:

    <script lang="ts">
        import { type IconType, gear, house } from "./icons"
    
        import GenericIcon from "./GenericIcon.svelte"
    
        snippets.push((selected) => Icon({ icon: gear, color: selected ? "blue" : "neutral" }))
        snippets.push((selected) => Icon({ icon: house, color: selected ? "blue" : "neutral" }))
    </script>
    

    Now this would solve all of the above issues/limitations/problems at once, plus it would improve/add composability. Which, to my belief, is highly advisable.

    With the above implemented, even the following code should be possible:

    <script lang="ts">
        // even this should be possible:
        const genericIcon = (icon, selected) => Icon({ icon, color: selected ? "blue" : "neutral" })
        snippets.push((selected) => genericIcon(gear, selected))
        snippets.push((selected) => genericIcon(house, selected))
    
        // and also this should be possible:
        const genericIconFactory = (icon) => {
            return (selected) => Icon({ icon, color: selected ? "blue" : "neutral" })
        }
        snippets.push(genericIcon(gear))
        snippets.push(genericIcon(house))
    </script>
    

    Conclusion

    I believe in a future where authors are more powerful using Svelte than ever, having the ability to compose UI in a more advanced and flexible way.

    I love the way Svelte looks, works and behaves, its simplicity is important to us all.

    But being powerful, dynamic and flexible is important too. That's why many reach for other frameworks, like React or now even Ripple. I think Svelte should provide equal "power" to the user to compose UI, and not "stand in the way" and require the user to use these cumbersome workarounds (see above).

    Dream big

    'Choose the right tool for the job' is sensible but boring advice.

    It makes us small in our ambitions. I want us to dream bigger. I don't want to feel like my tools can't handle evolving requirements, or > that if I want to dabble in a new field I need to learn an entirely new way of working first.

    Even if it turns out to be unachievable, I find it valuable to ask the question 'what would it take for SvelteKit to be the best framework for any app?', whether it's purely static content, or a realtime multiplayer app, or an offline-first productivity app, or even something built for an augmented reality headset.

    From "Tenets" by @Rich-Harris

    Who is this?

    I have used Svelte for 3+ years to make GroupTube. A website that is also packaged as a mobile app.

    I've created multiple "View Controllers" for "Modals", "Tabs" and similar kinds of interfaces. I ran into the limitations discussed above many times during this.

    (See comments in #10678 for some of it.)

  • Get svelte version from svelte/compiler adds a large amount of code to the build...

    import { VERSION as svelteVersion } from "svelte/compiler";
    

    I've seen this issue before but can't find it anymore. Doing this import adds a lot of code to build, around 600kB I'm not sure why and all I want is the version of the compiler...

    Perhaps importing from 'svelte/compiler' is not the way to go about it but then the docs should be updated?

    Anyone else seen this?

  • Missing Conditional Rendering

    Hi, the template syntax: https://svelte.dev/docs/svelte/if is great. But imagine if there are many lists:

    {#if maybe}
        <ul>
            {#each { length: 999 }, i}
                <li>{i}</li>
            {/each}
        </>
    {/if}
    

    This might not efficient to the DOM, especially if the condition keep being toggle like a sidebar.

    Is there a feature like Vue: https://vuejs.org/guide/essentials/conditional.html#v-show where it only use CSS to hide it?

    I know I can use $state() and use class like the doc did: https://svelte.dev/docs/svelte/class But it's just not convenient. Is it possible to do something like:

    {#show maybe}
        <ul>
            {#each { length: 999 }, i}
                <li>{i}</li>
            {/each}
        </>
    {/if}
    
  • Move "placeholder UI for async work" functionality from `<svelte:boundary>` to `{#await}`, or to a new block `{#async}`.

    It's been said that "[Users] are good at finding problems, but not solving them."

    I feel like I've run into a small problem with Svelte, but I'm not entirely sure if my idea for fixing it is the best way of dealing with it.

    Therefore, I will start by describing the issue, and leave the feature request until the end. My hope is that writing this down will spark some discussion and maybe lead to a better implementation.

    If you would rather skip directly to the proposal, this link should let you jump to it. Edit: It doesn't work, you'll have to scroll down to "Proposal" yourself. Sorry!


    Background

    I am in a situation where I am teaching Svelte to others that have only ever written vanilla HTML and JavaScript. I am still pretty new to Svelte myself, but I think Svelte does a fantastic job of being approachable and easy-to-use for these types of users.

    Something I really appreciate about the new async Svelte is how it pushes developers to think about what data needs to be rendered immediately, and what data can be relegated to being fetched asynchronously at runtime.

    For example, it makes sense that calling await on a promise will (essentially) halt loading until the asynchronous work is done.

    <script>
        let result = await AsyncWork(); // Page won't load until AsyncWork() is complete.
        // This is good if the result is critical to the page and needs to be there no matter if the viewer has JavaScript enabled or not.
    </script>
    

    It also makes sense that not calling await will continue execution:

    <script>
        let task = AsyncWork(); // `task` is a Promise. Page will load even if AsyncWork() isn't done.
    </script>
    

    This is a typical entry point for the extremely common web design pattern of displaying a placeholder, loading spinner, or some other sort of "skeleton" UI that is eventually replaced when the asynchronous work is complete. This pattern shows up everywhere; I think you can imagine it without me citing any specific examples.

    For now, I've begun calling this the "async placeholder" pattern — please forgive me if there already exists a more official term for this.

    Svelte currently offers three possibilities for accomplishing this pattern. From what I've seen, this is also typically the order in which new developers discover them.

    1. Awaiting the asynchronous work in an if (browser) ... check, or some other case that only executes at runtime like $effect(), then using {#if} blocks in the markup to handle the various states of the promise.

      • This is very explicit and easy to comprehend for those new to Svelte, but it tends to be verbose and not scale well when there are many promises floating around, or if there are sections of a page that depend on multiple promises.

      • It also often brushes shoulders with the "loading variables" design, e.g. setting, resetting, and rendering markup based on an isLoading or isPending variable. In my opinion, outside of very niche circumstances, this variable-heavy style tends to feel like bloat and is a regression from Svelte's reactive states. Instead of personally managing and querying a middleman variable, why not focus on querying the change-able state directly while letting Svelte handle the updates for you?

    2. Using an {#await} block.

      • This is more concise, but the deprecation of {#await} and replacing of {@const} is currently under consideration, which leads to questions about how to "properly" implement the "async placeholder" pattern.

      • I've also noticed that there tends to be a little bit of hesitation when using multiple {#await} blocks on the same promise. I feel like it might be due to the fear of an error from (#)await-ing the same promise twice. Of course, this is not a real problem — you can {#await AsyncWork()} as many times as you want — but maybe it might be worth saying this explicitly on the documentation?

    3. Using a <svelte:boundary> with a pending() snippet.

      • This seems to be the option that the Svelte community is currently leaning towards.

    However, I think using <svelte:boundary> in the context of achieving the "async placeholder" design pattern is very unintuitive.

    Placeholders and asynchronous rendering have become so frequently used in web design that it honestly feels more like a matter of page layout and composition ("design", basically), and not some exceptional case that would warrant the use of a "special element" (as listed in the Svelte docs).

    Originally, <svelte:boundary> was for "walling off" parts of an application for error-handling, almost like a section-specific catch statement. But now, I feel like its purpose has been diluted with this additional duty of processing placeholder UI, the frequency of which contrasts with how infrequently a developer actually needs a page-specific universal error-catcher.

    Of course, "how something feels" is subjective and probably shouldn't be a blocker when it comes to making things work. But Svelte Tenet #2, "Optimise for vibes", says it does matter, at least to a certain extent. As someone that is tasked with explaining the merits and intuitive-ness of Svelte to others, I really think the usage of <svelte:boundary> in this particular use case should be re-evaluated.


    As a bit of an aside, here's how I usually explain Svelte's syntax in order to make them easier to understand and remember:

    • "$...() are runes, Runes are Reactive, and reactivity is a way of handling $tates (states)."

    • {#...} blocks declare conditional markup.

      • {#if} is self-explanatory.
      • {#each} depends on the state (contents) of an enumerable.
      • {#key} depends on the state of an expression.
      • {#await} depends on the state of a Promise.
      • {#snippet} depends on the state (arguments) of the corresponding {@render}.
    • {@...} blocks inject data.

      • What {@render}, {@html}, {@attach}, {@const}, and {@debug} all have in common is that they involve attaching more data to wherever they show up.

    Of course, this isn't perfect, and most certainly isn't the only way to interpret the different syntax elements of Svelte. But framing things in this way has been rather effective when teaching others how to use the framework.

    And when looking at it from this perspective, it's easy to see how <svelte:boundary> doesn't quite fit as something that needs to be used regularly throughout a page just to achieve the "async placeholder" design pattern. Rendering placeholders is conditional markup — "if the data isn't ready yet, show the placeholder", "if the asynchronous work is done, show the content". Purpose-wise and usage-frequency-wise, this would fit much more appropriately with the {#...} block group.

    Furthermore, the updated <svelte:boundary> doesn't quite seem to fit in with the other <svelte:...> special elements. These really do feel special: most of them must be at the top level of a component, and can only show up once. (Note: the documentation for <svelte:options> doesn't explicitly say that it must be at the very top of the component definition, but it seems to be the convention and the formatter will always push it to the top.) The exception is <svelte:element>, which can appear anywhere in the markup section repeatedly. But this makes sense because it represents a generic/unknown element, and it serves a pretty rare and niche use case.

    When the purpose of <svelte:boundary> was only to catch unexpected-yet-non-breaking errors, it was infrequent enough that it truly did feel like a "special element". Seeing one was a big flag, like a warning: "Hey, something COULD potentially go wrong here, but we don't know what and we don't want the application to spontaneously combust if it happens — tread with care!" However, now that it's been assigned to also handle placeholder markup with the pending() snippet, it is the go-to solution for the very common "async placeholder" pattern, making it show up far too often to be considered a "special element".

    In short, its significance has diminished, and its purpose has blurred and blended with the other syntax groups.


    Additionally, other developers have also noted that <svelte:boundary> isn't a drop-in replacement for {#await}. One usability issue is that it doesn't automatically refresh its contents if the tracked expression(s) have updated. In order to handle this, the docs recommend using $effect.pending().

    Unfortunately, this means that the "async placeholder" pattern requires:

    1. A special element, <svelte:boundary>,
    2. A snippet, in the form of {#snippet pending()},
    3. An {#if} block, and
    4. A rune (extension), $effect.pending().

    This is three different types of Svelte markup (four, if you consider {#snippet}s to be their own thing since they have some pretty unique and framework-specific rules) to handle this very common design pattern. And we will need to repeat all of this for every instance.

    Again, it just doesn't feel very intuitive for someone new to Svelte.


    Proposal

    What I am ultimately trying to suggest is a a way of simplifying things for developers:

    • If you need markup dependent on asynchronous work to be there on page load, await it in the <script> block.

    • If you want the page to load first, then add the markup afterwards: throw everything into an {#async} block.

    I'm not sure if this feature would warrant a whole new block — maybe we could get away with upgrading {#await} instead of deprecating it. But I think {#async} would let us escape the baggage of await halting execution.


    This proposal assumes acceptance of #17687 and #16490.

    An {#async} block won't render its primary content until all promises directly referenced within it have resolved.

    While the promises are still resolving, content within an optionally-provided {:pending} block will be shown.

    {#async}
        {let result = await AsyncWork()}
        <p>The result is {result}.</p>
    {:pending}
        <p>Still doing work, hang on...</p>
    {/async}
    

    This should also work with multiple promises. If the state of any promise within the block somehow changes back to being unresolved, the block returns to rendering the {:pending} section.

    {#async}
        {let result1 = await AsyncWork()}
        {let result2 = await MoreAsyncWork()}
        {let result3 = await EvenMoreAsyncWork()}
        <p>All three tasks are complete!</p>
    {:pending}
        <p>We're waiting on something...</p>
    {/async}
    

    It would also be nice to be able to simplify this if we don't particularly care about the results. (Not sure how feasible this particular syntax is, though...)

    {#async AsyncWork(), MoreAsyncWork(), EvenMoreAsyncWork()}
        <p>All three tasks are complete!</p>
    {/async}
    

    If it wasn't clear, the promises referenced in the {#async} block should start the moment the block is rendered, but the processing of the document isn't halted.

    Just like the existing {#await} block, something like the following should allow developers to conveniently handle refreshing / redoing async work.

    <script>
        let task = $state(AsyncWork()); // Not awaited.
    </script>
    
    {#async task}
        <p>Task is done!</p>
        <button type="button" onclick={() => task = AsyncWork()}>
            Do it again!
        </button>
    {:pending}
        <p>This line is shown at the beginning and when the button is clicked.</p>
    {/async}
    

    If a non-promise is "started" in an {#async} block, it is treated as a promise that resolves immediately. This lets you create async placeholders for content that have already loaded.

    <script>
        let result = $state(await AsyncWork()); // Awaited, so it's guaranteed to be loaded from the start.
    </script>
    
    {#async result}
        <p>Here is the result: {result}</p>
        <button type="button" onclick={() => result = AsyncWork()}>
            Do it again!
        </button>
    {:pending}
        <p>This won't show at the start, but it'll appear when the button is clicked.</p>
    {/async}
    

    Here is a version of the previous example that doesn't involve passing result to the {#async} block declaration. Unfortunately, I think it would have to be mandatory to include result somewhere in the {#async} block, as otherwise there wouldn't be a connection between the two.

    <script>
        let result = $state(await AsyncWork());
    </script>
    
    {#async}
        <p>We have to put the result somewhere: {result}</p>
        <button type="button" onclick={async () => result = await AsyncWork()}>
            Do it again!
        </button>
    {:pending}
        <p>This won't show at the start, but it'll appear when the button is clicked.</p>
    {/async}
    

    And of course, it should be possible to use multiple {#async} blocks for the same promise.

    <script>
        let task = AsyncWork();
    </script>
    
    {#async task}
        <p>This is something dependent on the completion of the task.</p>
    {/async}
    
    {#async task}
        <p>This is another thing dependent on the task, but shows up elsewhere in the document.</p>
    {/async}
    

    I'm trying to avoid bringing up nitty-gritty details that, frankly, I don't have the qualifications to be speaking about... but it would be nice if the compiler could somehow see repeated async calls and cache the results.

    <script>
        let result = await AsyncWork(); // Awaited, therefore loaded.
    </script>
    
    {#async}
        {// At initial page load, the next line should re-use the value from the top.}
        {const data = await AsyncWork()}
        <p>The data is {data}</p>
    {:pending}
        <p>This won't ever show up because AsyncWork() is only run once at the start.</p>
    {/async}
    

    And, just to throw this out there, maybe it could be possible to assign values within the {#async} block declaration? But this might introduce too much complexity / too many ways to do the same thing...

    {#async result = await AsyncWork()}
        <p>{result}</p>
    {:pending}
        <p>This will show up at the start; AsyncWork() will be started but won't block.</p>
        <p>Remember, as long as it's within the {#async} block, it won't block execution. Very straightforward!</p>
    {/async}
    

    Isn't this just <svelte:boundary> smashed together with {#await}?

    Yes. I think it is nice.

    Does this replace <svelte:boundary>?

    No, but I think it would be good to slowly migrate the "provide UI that should be shown when await expressions are first resolving" functionality to the new {#async} block or upgraded {#await} block (if we go that route).

    This would return <svelte:boundary> to its original, unique purpose (catching errors), while we give developers an intuitive solution for handling asynchronous work: "Throw it in an {#async} block."


    Note: I do worry a little bit that a feature like this might promote the blind creation of more SPAs (which don't support script-less browsers), but the matter should be alleviated if we clearly state the difference between "await in the script block" and "await in an {#async} block" (the former is blocking and good for important data, the latter is non-blocking and won't show up if the viewer has disabled JavaScript).

  • Why bind to index instead of value in a component with $bindable?

    Hello everyone,

    I am learning Svelte at the moment and have come across this behavior and cannot find an explanation to why the compiler wants me to write the code like this:

    I have a component TodoList.svelte that uses another component TodoItem.svelte.

    TodoList.svelte

    <script>
        import TodoItem from "./TodoItem.svelte";
    
        let { todos = $bindable(), removeTodo } = $props()
    </script>
    
    <ul>
        {#each todos as todo, i}
            <TodoItem bind:todo={todos[i]} {removeTodo}/>
        {/each}
    </ul>
    

    TodoItem.svelte

    <script>
        import { slide } from "svelte/transition";
        
        let { todo = $bindable(), removeTodo } = $props()
    </script>
    
    <li transition:slide>
        <input type="checkbox" bind:checked={todo.completed}>
        <input type="text" bind:value={todo.text}>
        <button onclick="{() => removeTodo(todo)}">x</button>
    </li>
    

    In TodoItem.svelte, I am binding to todo as I want to mutate it by activating/deactivating the checkbox and so mutate todo.completed.

    In TodoList.svelte I need to use bind:todo={todo[i]} or I will get a warning about the mutability of todo and that I should use bind.

    Why do I need to pass the reference to the right todo object in the each loop by its index instead of directly using the value, like:

    {#each todos as todo, i}
        <TodoItem bind:todo={todo} {removeTodo}/>
    {/each}
    

    Thanks in advance! I am still learning and this somehow stopped me as I want to understand but couldn't find an entry to the right topic in the documentation.

  • NX first class support for Sveltekit

    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?

  • Recent releases often introduce bugs

    We have been using Svelter for several years up until now. We usually install patch releases automatically in our build process. This was not a problem for many years, since I seldom encountered any bugs with an update from e.g. X.X.23 to X.X.24

    I have now encountered breaking bugs in recent patch releases for the third time in the last few months.

    One update broke select boxes when the list of options changes. This was immediately visible, because select boxes just became blank after choosing an option in many of our applications.. A fix is still pending review. https://github.com/sveltejs/svelte/issues/17148

    Another update stopped layerchart from working by breaking the build completely and had to be fixed by a workaround from layerchart devs. https://github.com/sveltejs/svelte/issues/17750

    The most recent update can break the invariant of if-blocks inside of snippets in components. I get null-pointer exceptions inside a svelte if-block which checks if the variable is null. https://github.com/sveltejs/svelte/issues/17866

    All this gives the impression that something changed in how svelte is developed. I get the feeling new features are shipped eagerly and not tested sufficiently. It might have to do with LLM-assisted development, which can quickly generate code satisfying all tests, but subtly wrong because it lacks the insight of a seasoned developer.

    Do you share this impression?

Loading Svelte Themes