Skip to content

Remote form() result persists after navigation #14802

Description

@mquandalle

Describe the bug

The docs state that form() result values are ephemeral and "will vanish if you navigate away", but they actually persist when returning to the page.

Reproduction

https://stackblitz.com/edit/sveltekit-form-ephemeral-state-bug

Logs

System Info

System:
    OS: macOS 15.5
    CPU: (8) arm64 Apple M2
    Memory: 80.34 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.12.0 - ~/.nvm/versions/node/v22.12.0/bin/node
    npm: 9.6.4 - /opt/homebrew/bin/npm
    pnpm: 10.18.3 - /opt/homebrew/bin/pnpm
    bun: 1.3.0 - ~/.bun/bin/bun
  Browsers:
    Chrome: 141.0.7390.108
    Safari: 18.5
  npmPackages:
    @sveltejs/adapter-auto: ^6.1.0 => 6.1.1
    @sveltejs/kit: ^2.43.2 => 2.47.3
    @sveltejs/vite-plugin-svelte: ^6.2.0 => 6.2.1
    svelte: ^5.39.5 => 5.41.4
    vite: ^7.1.7 => 7.1.12

Severity

annoyance

Additional Information

No response

Activity

  1. added theissue type on Oct 24, 2025
  2. sillvva commented on Oct 25, 2025

    @sillvva
    Contributor

    @dummdidumm I think the issue here is that the way remote form works is you're importing an instance of a remote form rather than a function that creates a new instance. Since the import is cached in memory even as you navigate around, the values in that instance are retained.

    If it were a function that you call to create an instance, it would create a new instance each time the page is loaded and only the function would be cached in memory.

    So instead of:

    <script lang="ts">
      import { todoForm } from "./form.remote.ts";
    </script>
    
    <form {...todoForm}> <!-- same instance every time -->
      ...
    </form>

    It should be:

    <script lang="ts">
      import { todoForm } from "./form.remote.ts";
      const form = todoForm(); // creates new instance every time
    </script>
    
    <form {...form}>
      ...
    </form>

    I tested this out with a local copy of sveltekit and it seemed to work, although I was unable to get the types and .remote.ts export limitation working correctly.

  3. iatrophobic commented on Oct 25, 2025

    @iatrophobic

    I have a remote form wrapper component that lets me easily pass custom on success, error, etc...hooks to a custom enhance function and was going crazy thinking I was doing something wrong lol. Same bug noticed here running kit v2.43.2

  4. sillvva commented on Oct 25, 2025

    @sillvva
    Contributor

    This is also a temporary workaround that I'm using. Using a unique form id with .for() creates a new instance on each page load. .for() has a built-in feature to delete the current instance when unmounted.

    Ultimately, though, I think making it a function would be a better DX.

    Image

  5. mquandalle commented on Oct 25, 2025

    @mquandalle
    Author

    If the goal is to keep the existing API without instanciating a new form on each page, maybe onNavigate could be used to reset the form (but I don't know if it runs if we stay on the same page but add for instance a query parameter to the url, which would be unwanted)

  6. sillvva commented on Oct 25, 2025

    @sillvva
    Contributor

    With a function, you could still cache a form instance to get the current behavior by exporting the instance from a module instead of calling it directly from the page/component.

    // $lib/remote/forms.ts
    import { todoForm } from './forms.remote.ts';
    
    export const cachedTodoForm = todoForm();

    There's also PR #14779 awaiting approval to add the ability to programmatically reset the state(s) of a form instance.

  7. hyunbinseo commented on Dec 26, 2025

    @hyunbinseo
    Contributor

    @sillvva Thank you for the workaround!

    So SvelteKit remote form allows multiple instances of a form:

    you can create separate instances of a form function via for(id)

    {#each await getTodos() as todo}
      {@const modify = modifyTodo.for(todo.id)}
      <form {...modify}>

    However, this doesn't have to happen inside an each loop.

    Before

    <script>
      import { PublicSendCodeSchema } from '.';
      import { sendCode } from './index.remote';
    </script>
    
    <form {...sendCode.preflight(PublicSendCodeSchema)}></form>

    After

    $props.id() seems to work.

    <!-- src\routes\login\+page.svelte -->
    
    <script>
      import { PublicSendCodeSchema } from '.';
      import { sendCode as _sendCode } from './index.remote';
    
      const uid = $props.id();
    
      const sendCode = _sendCode.for(uid);
    </script>
    
    <form {...sendCode.preflight(PublicSendCodeSchema)}></form>

    Note

    I would love to create a new instance by default.

    Login page persisting after (login → log out with login page redirect) was not intuitive.

  8. akqira commented on Feb 15, 2026

    @akqira

    Hi,
    I faced the same situation this week. Thanks @sillvva for your workaround using .for()
    A bit disappointed and then frustrated to have such behavior (issues persisting even after navigating to another route and trying back).
    So solution was to use :

    {@const myForm = addLibraryItem.for(Math.random().toString(36).substring(2, 15))}

    I don't know if it affect the memory/cache but for now, each time the user will add an entry via this remote function a new form will be used. If user refresh the page then all is reset correctly

    Waiting for your PR @sillvva 🥇

  9. added
    formsStuff relating to forms and form actions
    on Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    formsStuff relating to forms and form actions

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions