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.
  • How to handle `state_referenced_locally` for static props

    I'm using Svelte 5 within an Astro project.

    I pass a locale prop from Astro to a Svelte component, and this locale never changes during the component's lifecycle.

    <script>
      import { getRelativeLocaleUrl } from 'astro:i18n';
      import { getTranslator } from '$lib/i18n';
    
      let { locale } = $props();
    
      // Warning: state_referenced_locally
      // But strictly necessary for initialization
      const t = getTranslator(locale); 
      const homeUrl = getRelativeLocaleUrl(locale, '/');
    </script>
    
    <a href={homeUrl}>{t('home')}</a>
    

    Should I wrap these in $derived() even though I know they will never re-calculate?

  • Testing svelte:head content in unit tests

    This is perhaps a silly question, but it's something I ran into at work.

    We have a couple of components which are using JS libraries to defer the displaying of some content within our written articles and blogs.

    There is also a unit test, broken down to it's very basic pieces, you get something that looks like this:

    // special.svelte
    <script>
     // Other code here
    </script>
    <svelte:head>
      <script>
        // some required args for the library
        window.SOME_LIBRARY = { disable_autoload: true };
      </script>
      <!-- not the actual library, but to show the point that something has to load here -->
      <script src="https://code.jquery.com/jquery-3.7.1.slim.min.js" defer></script>
    </svelte:head>
    
    <!-- other HTML here -->
    

    In practice, this works fine when testing on a browser, but someone well before I got there created a test that looks something like this

    import { render } from '@testing-library/svelte';
    import { describe, expect, it } from 'vitest';
    import Special from './special.svelte';
    
    describe('Special', () => {
      it('Does its special thing', async () => {
        render(Special);
        expect((window as any).SOME_LIBRARY).toBeDefined();
        expect(
          document.head.querySelector(
            'script[src="https://code.jquery.com/jquery-3.7.1.slim.min.js"]',
          ),
        ).toBeInTheDocument();
      });
    });
    

    Which fails, and writing the entire DOM to the console shows me

    <html>
      <head>
    
    
      </head>
      <body>
        <div>
          <div>
            Loading...
          </div>
        </div>
      </body>
    </html>
    

    It seems that in svelte 5 (I haven't been able to test on svelte 4) the <svelte:head> contents are not being applied in test environments.

    Anyone got any ideas how I can fix this?

  • Is there a something like vue's mode and appear props of transition?

    Vue has props in transtition mode - https://vuejs.org/guide/built-ins/transition#transition-modes appear - https://vuejs.org/guide/built-ins/transition#transition-on-appear are there analogs for svele? As I see, svelte always use 'default', so removed and added DOM elements both exists while playing transition and always plays on mount

  • Svelte Toolbar

    [!NOTE] this post is a collection of ideas and goals and things will be refined based on the discussion that follows, nothing is set in stone yet.

    svelte toolbar

    As Rich mentioned briefly during his svelte summit talk we are working on a toolbar to improve DX and allow better insights into svelte applications.

    Goals

    available everywhere

    regardless of how you use svelte, adding the toolbar should give you access to the tools in our ecosystem

    • The toolbar itself is going to be part of the svelte package under a new subpath export svelte/toolbar.
    • First party tools added automatically via svelte/toolbar or other packages within the org (eg bundler plugins)

    customizable

    While we are going to provide first party tools, we also want to provide an api to add third party tools and allow customization

    add tools

    • libraries or packages for svelte can ship with dedicated tools
    • community can add useful generic tools
    • you can add custom made ones for your app

    configure

    The toolbar itself and each tool has a configuration that can be modified by invoking a function provided on svelte/toolbar The configuration is going to be stored locally so you can tailor it to your needs and it stays that way. Possible storage locations would be localstorage, indexeddb or .env.local files.

    mode aware

    Most tools are going to be available during dev, but some can also be used in a production build.

    powerful

    • access svelte build-time information from the svelte compiler
    • access svelte runtime information
    • integrate with dev server functionality

    Planned tools

    first release

    svelte inspector

    to be ported from vite-plugin-svelte , its functionality is going to remain the same, but instead of hardcoding how file editors are opened by a call to a vite middleware, it is going to leverage the devserver integration

    toolbar config editor

    visual editor for the toolbar config, with options to persist

    future releases

    reactivity graph viewer

    $inspect is nice and surgical, but it would be even nicer if there was a way to visualize the reactivity graph and more easily follow dependencies through your app. Solid already has a tool for this and so should we

    sveltekit route viewer

    params, matchers, layout groups, the file system tree can become a bit messy. A dedicated ui with links to open the relevant files can help understand and work with your application structure.

    component hierarchy viewer

    The original svelte devtools browser extension had this view, and we can bring it back.

    your idea here

    please share ideas for tools you'd like to have/build and any apis they might need. now is the time to shape the foundation

    the owl

    The toolbar

    The toolbar itself is going to provide basic common features to the tools and renders them with provided name&icon. Of course it is going to be a svelte component and to avoid colliding with your application it will be mounted on document.documentElement outside of body by default, which should avoid collisions with your app in most cases.

    A tool

    A tool needs to be registered with the toolbar and receives api & configuration. Optionally it can provide its own svelte component for ui. If the toolbar is going to add this component or the tools is responsible for mounting it is still up for discussion.

    How to add it

    Ideally, bundler plugins are going to inject the toolbar to avoid the need for putting code into your app yourself (like svelte-inspector is added today) and the tools just show up as configured. But manually putting them in your root layout can work as well. The hardest one is adding them for production, this might require a web extension and building with a special flag so it can aquire a reference to the toolbar api.

    Feedback & Ideas wanted!

    If you want to build a tool, what api do you prefer. Should a tool always be a svelte component or should it be more similar to a vite plugin with an initializer function and hooks?

    Do you think tools should be aware of each other and able to collaborate?

    What are the most important tools you want to use?

    Would you prefer a web extension with ui separately in the devtools tab or is rendering in the apps window ok?

  • svelte-gui - component library & app shell

    Heyy, made a boilerplate template to kickstart web app development with some prebuilt tailwind components and utilities:

    Form validation, view-transitions, staggered animations, prebuilt auth, docs page and many more... check the repo out :D

    https://github.com/magooney-loon/svelte-gui

    Web demo: https://svelte-gui.vercel.app/

  • Recursive Components vs Snippits. Which is more performant?

    so, i am building a file tree component in svelte which takes an array of objects whith this data structure

    export interface FileNode {
      name: string;
      path: string;
      isDirectory: boolean;
      children: FileNode[];
    }
    

    i built a fully working minimal file tree compoenent with recursive component this (simplified)

    <script lang="ts">
      // imports itself
      import ItemsRenderer from './items_renderer.svelte';
      import type { FileNode } from '@/types';
    
      let { file_tree }: { file_tree: FileNode[] } = $props();
    </script>
    
    {#if file_tree.length}
      <ul>
        {#each file_tree as node (node.path)}
          <li>
            {#if node.isDirectory}
              <details>
                <summary>
                  {node.name}
                </summary>
                <ItemsRenderer file_tree={node.children} />
              </details>
            {:else}
              <div>
                {node.name}
              </div>
            {/if}
          </li>
        {/each}
      </ul>
    {/if}
    

    and also with snippits

    <script lang="ts">
      import type { FileNode } from '@/types';
      let { file_tree }: { file_tree: FileNode[] } = $props();
    </script>
    
    {#snippet folder_node(nodes: FileNode[])}
      <ul>
        {#each nodes as node (node.path)}
          <li>
            {#if node.isDirectory}
              <details>
                <summary>
                  {node.name}
                </summary>
                {@render folder_node(node.children)}
              </details>
            {:else}
              <div>
                {node.name}
              </div>
            {/if}
          </li>
        {/each}
      </ul>
    {/snippet}
    
    {#if file_tree.length}
      <div class="overflow-y-auto">
        {@render folder_node(file_tree)}
      </div>
    {/if}
    

    now, some things that i didn't include in the code is that,

    • in the recursive compoenent approach, i am passing the same props that the parent has. so essentially, prop drilling down the depth of the file tree does that affect performace, compared to not prop driling and using snippits?

    i wonder which one is more performant?

  • Memoized functions (client side equivalent to `query` remote functions)

    I am proposing a new primitive (or an enhancement to the upcoming resource API) that enables on-demand, async, memoized, and reactive client-side data fetching.

    The goal is to bring the developer experience of SvelteKit’s remote functions (specifically the caching/sharing mechanism) to client-side logic, allowing shared state across components without the limitations of setContext or the complexity of manual cache invalidation.


    Proposed API

    The usage would look similar to a query remote function but designed for client-side logic (e.g., inside .svelte.js files).

    Option A: String Key

    import { online } from 'svelte/reactivity/window';
    import { memoize } from 'svelte/reactivity'; // Hypothetical import
    
    export const getTodos = (id) => {
      return memoize(`/todos/${id}`, async () => {
        // Track svelte signals:
        if (!online.current) return null;
        
        // Track signals after awaits (e.g. react to remote function refreshes)
        const user = $derived(await getUser());
        if (!user) return null;
        
        const todos = fetch(`/api/todos/${id}?user=${user.id}`).then((res) => res.json());
        
        // Since they have their own lifecycle, maybe even have an on/off notifier:
        $effect(() => {
          // e.g. start websocket connection
          return () => {
            // e.g. cleanup websocket connection
          }
        });
        
        return todos;
      });
    }
    

    Option B: Schema/Auto-key (Remote function style)

    export const getTodos = memoized(z.string(), async (id) => {
      // ...
    })
    

    Motivation

    Currently, sharing async state in and outside the component tree is friction-heavy. While setContext / getContext is the standard solution for SSR-safe shared state, it imposes strict limitations in an async environment:

    1. Component coupling: It must be called inside a component tree.
    2. Async blocking: It cannot be called after an await expression.
    3. Function boundary requirements: To maintain reactivity, state must be passed via getters (e.g., setContext('key', { get value() { return signal }})).

    This proposal asks for a primitive that allows data to be defined globally (or in shared modules) and consumed locally, with the framework handling the lifecycle and cache sharing.


    I have attempted to implement this pattern in userland, but I have hit specific roadblocks regarding how Svelte 5 handles reactivity across async boundaries.

    1. The "Async Gap" in .svelte.js files

    In Svelte components, $derived(await ...) magically handles signal tracking across await boundaries. However, replicating this inside standard .svelte.js functions is inconsistent.

    Although using $derived inside a function technically compiles, the behavior is flaky. Reactivity often fails to track signals correctly if the execution involves complex async flows, or it requires multiple signal changes to "wake up" the tracking.

    See reproduction in Playground

    2. $effect.root does not support async

    To memoize a resource that might be called outside a render effect (e.g., in an event handler), we need to create a root scope using $effect.root. However, $effect.root cannot contain async execution.


    I am aware of the upcoming resource primitive in #16960. While exciting, the current design seems to rely exclusively on manual invalidation (.refresh()).

    If I have a resource that depends on other resources, I have to manually cascade .refresh() calls. Ideally, the resource should track signals (including other resources) used in its "run" function and automatically re-run when dependencies change, keeping the value up to date without manual intervention.

  • Undefined flicker in library store with async svelte

    Hi, I have observed a behavior which I cannot really get my head around and thought I'd ask you guys what the issue might be:

    // I do some data fetching here. The result is the conferenceData observable which
    // allows subscribing to return values via svelte store syntax
    // using the new async svelte, I use await which will guarantee the observable to have a value present
    const conferenceData = await client.query.conferenceUsers({
      ...
    });
    

    when I now inspect the subscribed value $inspect($conferenceData) I see undefined and then immediately the actual value when I look into my browser console. Thinking this might be because the initial value might somehow not be set correctly, I wrapped this into a readable which resolves the problem:

    const conferenceDataStore = readable(conferenceData, (set) => {
      set(conferenceData as any);
      const sub = (conferenceData as any)?.subscribe?.((v: any) => set(v));
      return () => sub?.unsubscribe?.() ?? sub?.();
    });
    
    $inspect($conferenceDataStore)
    

    This never shows undefined.

    That's nice. I want to move this to my library so the above call will do this automatically. So I imported svelte/store and did exactly what I did above but in my data fetching library. And the undefined returned. So somehow it makes a difference if the store is created inside my component?!

    Anyone have any idea why this happens? I know async is still in beta and I'm not sure if this is an issue on my part or actually needs to be addressed. Thanks for your time!

  • Using a Component as an argument to another Component

    I'm just picking up Svelte with Carbon Components. I'm trying to do something like the following with Theme.

      <Theme
        bind:theme
        render="toggle"
        persist
        toggle={{
          themes: ["g10", "g90"],
          labelA: "Light",
          labelB: "Dark",
          hideLabel: false,
        }}
      />
    

    But instead of "Light" and "Dark" for labels I'd like to use Sun and Moon from carbon-icons-svelte for labelA and labelB. I'm wondering if it's just not possible, because of how the Theme component has been written; the labels being strings, and the icons being <svg>...</svg> nodes?

    Have I understood that correctly, or am I missing something?

Loading Svelte Themes