Skip to content

Layout shift when using {:else} with await on remote functions during SSR #17751

@timootten

Description

@timootten

Describe the bug

When using {#if await ...}{:else}{/if} blocks with SvelteKit remote functions (query from $app/server), a layout shift occurs during hydration despite both branches being prerendered on the server. Using two separate {#if} blocks instead of {:else} eliminates the layout shift. This issue only occurs with remote functions, not with regular async functions or promises.

Reproduction

Remote functions (test.remote.ts)

import { query } from "$app/server";

export const getTest1 = query(async () => {
  return false;
});

export const getTest2 = query(async () => {
  return "Hello World! 2";
});

Case 1: With layout shift (using :else)

<script lang="ts">
    import { getTest1, getTest2 } from "./test.remote";
</script>

{#if await getTest1()}
  Testing
{:else}
  {await getTest2()}
{/if}

<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>

Case 2: Without layout shift (using separate {#if} blocks)

<script lang="ts">
    import { getTest1, getTest2 } from "./test.remote";
</script>

{#if await getTest1()}
  Testing
{/if}
{#if !await getTest1()}
  {await getTest2()}
{/if}

<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>

Expected behavior

Both approaches should render identically during SSR and hydrate without layout shifts. The {:else} block should produce the same hydration result as using two separate conditional blocks with inverse conditions when using remote functions.

Actual behavior

  • Case 1 (with :else): Causes visible layout shift during hydration
  • Case 2 (separate {#if} blocks): No layout shift, smooth hydration
  • Important: This only happens with remote functions from $app/server, not regular promises

Reproduction

https://github.com/timootten/SvelteKit-Layout-Shift

Logs

System Info

System:
    OS: Windows 11 10.0.26100
    CPU: (16) x64 AMD Ryzen 7 5700X 8-Core Processor
    Memory: 17.35 GB / 31.91 GB
  Binaries:
    Node: 22.20.0 - C:\Program Files\nodejs\node.EXE
    npm: 10.9.0 - C:\Program Files\nodejs\npm.CMD
    pnpm: 10.18.1 - C:\Users\timoo\AppData\Local\pnpm\pnpm.CMD
    bun: 1.3.4 - C:\Users\timoo\AppData\Local\pnpm\bun.CMD
    Deno: 2.3.3 - C:\Users\timoo\.deno\bin\deno.EXE
  Browsers:
    Chrome: 143.0.7499.40
    Edge: Chromium (140.0.3485.54)
    Firefox: 144.0.2 - C:\Program Files\Mozilla Firefox\firefox.exe
    Internet Explorer: 11.0.26100.1882
  npmPackages:
    @sveltejs/adapter-node: ^5.4.0 => 5.4.0
    @sveltejs/enhanced-img: ^0.9.2 => 0.9.2
    @sveltejs/kit: https://pkg.pr.new/sveltejs/kit/@sveltejs/kit@966e232 => 2.49.1
    @sveltejs/vite-plugin-svelte: ^6.2.1 => 6.2.1
    svelte: 5.45.6 => 5.45.6
    vite: ^7.2.6 => 7.2.6

Severity

annoyance

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions