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.
  • Potential `$effect.server` rune?

    I've had a few projects recently using adapter-node where I'm using either streaming requests or websockets, and when state changes I need to push updates to connected clients. I get all excited to use runes, before remembering that $effect and $effect.root don't run on the server 🥲. I'm currently using old subscriber functions instead, and it's a much worse experience (It really shows how nice runes are by comparison!).

    I've been wondering if it would be possible (or even a good idea?) to create an $effect.server rune. I imagine it using it like this:

    class MyServerState {
        count = $state(0);
        connectedClients = new Set();
        disposeEffect = null;
    
        constructor () {
            this.disposeEffect = $effect.server(() => {
                for (const conn of this.connectedClients) {
                    conn.sendData(this.count);
                }
            });
        }
        
        dispose = () => {
            this.disposeEffect.?();
            for (const conn of this.connectedClients) {
                conn.disconnect();
            }
            connectedClients.clear();
        }
    }
    
    const serverState = new MyServerState();
    
    // Elsewhere ...
    serverState.connectedClients.add(clientConnection);
    serverState.count += 1;
    

    It would ONLY run on the server, and it returns a dispose function just like $effect.root, so it would not need to be wrapped in a root like $effect does. This probably wouldn't be a good idea for platforms that aren't adapter-node, so I guess in those cases it might get transformed into a no-op?

    Still not sure if it's a great idea. $effect is already a footgun so adding another effect rune shouldn't be done carelessly, but it would be really nice to be able to have server-side reactivity with runes 😅

  • Does it make sense to move pure functions to a `script module` in Svelte 5?

    In Svelte 4, the compiler hoisted pure functions even if they were not declared in script context="module". This was also mentioned in the documentation:

    Don't worry that we're redeclaring the foo function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition.

    Demo / Svelte 4.0.0 (example from Svelte 4 documentation)

    image

    But in Svelte 5, this is no longer the case, and I can't find any mention of this change anywhere.

    Demo / Svelte 5.46.0 (example from Svelte 4 documentation)

    image

    Demo / Svelte 5.46.0 as script module (example from Svelte 4 documentation)

    image
  • There should be a different rune for creating state with object arg: `$proxy({value: 1})`

    When state is given an object it compiles to a proxy object which can be passed to an external store which can read a property reactively.

    When given a scalar, it cannot be passed to a store unless it is in a getter.

    This is very confusing.

    Is there a reason why I shouldn't just use objects for all my state so that if I need to pass them to module stores I can?

  • Easily create derived state

    When using external stores, you can't just pass scalar state and use it reactively. But if its an object state then you can pass it and use $derived to read it.

    If you want to pass scalar state you have to use a getter function...or you have to create a store.

    It would be nice to have an easy way to create a store whose value is derived from some state in a component.

    <script>
    
    let value = $state()
    
    // a. Won't be reactive when passed to component.
    let item1 = $derived({value})
    
    // b. Current approach
    let item2 = $state({value: null})
    $effect(() => item2.value = value)
    
    // c. Proposal.
    let item3 = $derivedState({value})
    
    </script>
    
    <input bind:value={value} />
    
    <Component {item}/>
    

    It's easy to mistake $derived({value}) thinking it creates reactive state but it does not.

    This rune would make it easy to pass reactive scalar state to a store...making it easier to extract functionality.

  • `Cannot read properties of undefined (reading 'map')` when using context with a nested Promise object

    I'm trying to use context to bypass using load functions for some specific data to avoid sending a very large response on initial, server-rendered response.

    I saw in docs that I can set reactive objects to context, so I have tried to dynamically importing a module into a $derived object, setting it to context, and in subsequent components consume said context with the new experimental await feature.

    $derived because in my actual case I load data based on the path param. I expect it to work same as with $state.

    But I am getting undefined whenever I call the getter function!

    Here's the repro of the issue:

    https://github.com/sirkostya009/svelte-context-repro (navigate to /a/nested)

    I am not even sure if this is a bug or not. I have initially tried to just await import in the setContext call

    setContext(key, await import(`$lib/${params.key}.js`));
    

    but kept getting a "can only call setContext during component initialization" error so came up with a clever workaround that also doesn't work!

  • svelte 5 için daisyui arasındaki uyumluluk

    svelte 5 için daisy ui için en iyi stabil sürümü nedir

  • Recommended animation libraries for complex animations in Svelte / SvelteKit?

    I’m curious about animation options in the Svelte ecosystem beyond the built-in transitions and motion utilities.

    The official animations are great for simple UI interactions, but for more complex scenarios (timeline-based animations, scroll-driven effects, or advanced micro-interactions), are there any community-recommended libraries that work particularly well with Svelte or SvelteKit?

    I’ve seen mentions of things like GSAP or Motion One being used with Svelte, but I’m wondering if there are any Svelte-first or Svelte-friendly approaches that the community prefers, especially for larger apps.

    Would love to hear what people are using in production and why.

  • 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.)

  • Allow reactive state to be declared closer to its usage in templates

    Problem Statement

    Svelte requires that all reactive state must be declared in the <script> block at the top of the component. This creates separation between state declarations and their usage in the template, making code harder to read and maintain, especially in large components.

    Current situation:

    <script>
      // All state declarations bunched at the top
      let modalOpen = $state(false);
      let tooltipVisible = $state(false);
      let dropdownExpanded = $state(false);
      let searchQuery = $state('');
      // ... potentially dozens more
    </script>
    
    <!-- 200 lines later -->
    <div>
      {#if modalOpen}
        <Modal onclose={() => modalOpen = false} />
      {/if}
    </div>
    
    <!-- 100 lines later -->
    <div>
      {#if tooltipVisible}
        <Tooltip />
      {/if}
    </div>
    

    You end up constantly scrolling between the script block and template to understand what state controls which part of the UI.

    Desired Outcome

    Enable scoped (preferably, but not required), localized state declarations within the template itself, keeping state close to where it's actually used.

    This would allow developers to:

    • Declare state inline, near its usage
    • Scope state to specific sections of the template
    • Avoid polluting the script block with UI-local toggles
    • Make components more self-documenting and easier to refactor

    Possible Implementation (Example)

    One approach could be something like {#let} blocks:

    <div>
      {#let modalOpen = $state(false)}
        <button onclick={() => modalOpen = true}>Open</button>
        {#if modalOpen}
          <Modal onclose={() => modalOpen = false} />
        {/if}
      {/let}
    </div>
    
    <div>
      {#let tooltipVisible = $state(false)}
        <span onmouseenter={() => tooltipVisible = true}>Hover</span>
        {#if tooltipVisible}
          <Tooltip />
        {/if}
      {/let}
    </div>
    

    But this is just one possible syntax. The core request is for some way to declare reactive state closer to its usage point in the template, preferably with appropriate scoping.

    Use Cases

    • Modal/dialog open/close states
    • Tooltip visibility toggles
    • Accordion/dropdown expanded states
    • Form field-specific validation state
    • Local loading/error states for UI sections
    • Any UI state that's only relevant to a specific part of the template

    Additional Notes

    This isn't about replacing script-level state for shared/component-wide concerns—those should absolutely stay in <script>. This is about providing an option for truly local UI state that doesn't need to be component-wide.

    P.S. This is a human-made idea written with AI, and proofread/edited by HI (Human Intelligence).

Loading Svelte Themes