Skip to content

Streamed

olegivanov edited this page May 18, 2026 · 1 revision

Streamed

1. Overview

  • Name: Streamed
  • Purpose: Cross-adapter alias for the framework's native Suspense / await boundary. Renders a fallback while a pending Promise (or any descendant <Await>) is unresolved, then children with the resolved value.
  • When to use: Wrap a region of UI that depends on deferred SSR data when you want cross-framework symmetric naming. Inside a single framework, you can also use the native primitive (<Suspense> in React/Preact, {#await} in Svelte) directly.
  • Availability: All 5 framework adapters — @real-router/react/ssr, @real-router/preact/ssr, @real-router/solid/ssr, @real-router/vue/ssr, @real-router/svelte/ssr. The Svelte variant wraps the native {#await} block (no <Suspense> in Svelte).

2. Import and Basic Usage

<script lang="ts">
  import { Streamed, useDeferred } from "@real-router/svelte/ssr";

  import Spinner from "./Spinner.svelte";

  interface Review {
    id: string;
    text: string;
  }

  const reviewsPromise = useDeferred<Review[]>("reviews");
</script>

<Streamed pending={reviewsPromise}>
  {#snippet children(reviews)}
    <ReviewList items={reviews} />
  {/snippet}
  {#snippet fallback()}
    <Spinner />
  {/snippet}
</Streamed>

3. Props

Prop Type Required Default Description
pending Promise<T> Yes Promise to await — typically the return value of useDeferred<T>(key) or any user-supplied Promise.
children Snippet<[T]> Yes Render snippet for the resolved value. Receives the awaited value as its single positional argument.
fallback Snippet No undefined Snippet rendered while pending is unresolved. Omit for silent loading.

4. Behavior

Svelte implementation

Internally <Streamed> is a single {#await pending}…{:then value}…{/await} block:

{#await pending}
  <Fallback />
{:then value}
  <Children {value} />
{/await}

No additional logic — it exists purely for cross-adapter naming symmetry. Teams using multiple framework adapters (e.g. a monorepo with both React and Svelte apps) can reuse mental models when reading templates.

When to use <Streamed> vs {#await} directly

  • Prefer <Streamed> when you want consistent naming with other framework adapters in your codebase, or when sharing template patterns with documentation that uses cross-framework examples.
  • Prefer {#await} directly when you need the {:catch error} branch for rejection handling, or when the rest of the codebase uses Svelte-idiomatic patterns.

vs <Await>

Aspect <Streamed> <Await>
Promise source Caller passes pending directly Reads useDeferred(name) internally via key
Reactivity Promise reference must be reactive (typically $state or $derived) name is reactive via $derived(useDeferred(name))
Symmetry Cross-framework <Streamed fallback={…}> Cross-framework <Await name="…">
Use case Any awaitable, not only deferred Specifically reads SSR state.context.ssrDataDeferred[key]

You can nest them — <Streamed> as the boundary, <Await> for individual deferred reads:

<Streamed pending={useDeferred("hero")}>
  {#snippet children(hero)}
    <HeroSection {hero} />
    <Await name="reviews">
      {#snippet children(reviews)}
        <ReviewList items={reviews} />
      {/snippet}
    </Await>
  {/snippet}
  {#snippet fallback()}
    <ProductSkeleton />
  {/snippet}
</Streamed>

Server-side rendering behavior

Svelte 5 stable does NOT progressively chunk-flush HTTP for {#await} blocks. On the server:

  • <Streamed> emits the fallback branch in the initial HTML.
  • The full response ships in one TCP frame; no out-of-order chunks.
  • After hydration, the client re-runs the {#await} and resolves the promise, swapping in children(value).

This is RSC-like (server shell + client data) rather than React 19 / Solid streaming (chunked HTTP + OOO placeholders). See Streaming SSR for the framework-by-framework comparison.

No rejection handling

<Streamed> has no {:catch} branch. Rejections propagate to the surrounding {#await}/<Streamed> chain (i.e. they crash uncaught if no parent handles them). For fine-grained error UX, use raw {#await}…{:catch error}…{/await} or wrap with <RouterErrorBoundary>.

5. Examples

Pair with <Await> for deferred data

<script lang="ts">
  import { Streamed, Await, useDeferred } from "@real-router/svelte/ssr";

  import Spinner from "./Spinner.svelte";
</script>

<Streamed pending={useDeferred("hero")}>
  {#snippet children(hero)}
    <HeroSection {hero} />

    <Await name="reviews">
      {#snippet children(reviews)}
        <ReviewList items={reviews} />
      {/snippet}
      {#snippet fallback()}
        <Spinner label="Loading reviews" />
      {/snippet}
    </Await>
  {/snippet}
  {#snippet fallback()}
    <ProductSkeleton />
  {/snippet}
</Streamed>

User-supplied Promise (non-SSR)

<script lang="ts">
  import { Streamed } from "@real-router/svelte/ssr";

  // Plain promise — doesn't have to come from useDeferred.
  let dataPromise = fetch("/api/widgets").then((r) => r.json());
</script>

<Streamed pending={dataPromise}>
  {#snippet children(widgets)}
    <WidgetGrid items={widgets} />
  {/snippet}
  {#snippet fallback()}
    <Spinner />
  {/snippet}
</Streamed>

With error handling — use {#await} directly

{#await dataPromise}
  <Spinner />
{:then items}
  <WidgetGrid {items} />
{:catch error}
  <ErrorBanner message={error.message} />
{/await}

6. Gotchas

  • No {:catch} branch. Use raw {#await} for rejection UX.
  • fallback is a Snippet, not a Component. Different from <Lazy>, which takes a Component reference. {#snippet fallback()} is the Svelte-5-idiomatic way.
  • Server response is monolithic. Despite the "streaming" name, Svelte 5 stable returns the full HTML in one TCP frame. Deferred resolution happens client-side. See Streaming SSR for the model comparison.
  • The pending prop is not "captured at mount". It's reactive — if you pass a $state or $derived Promise reference, the {#await} re-runs when the reference changes.

7. Dependencies

  • No <RouterProvider> requirement — <Streamed> can wrap any Promise.
  • For useDeferred-fed Promises, a router with ssr-data-plugin must be mounted (see <Await> for context).

8. Related

  • Await — pair with <Streamed> to read deferred SSR data by key
  • useDeferred — composable that returns the underlying Promise
  • Streaming SSR — cross-framework streaming model comparison
  • Svelte Integration Guide — overview of the SSR surface
  • Lazy — lazy-load a single component (different concept: dynamic import() of a module)

Navigation

Home


Concepts


Getting Started


Router Methods

Lifecycle

Navigation

State

URL & Path

Events


Standalone API

Tree-shakeable functions — import only what you need.

Routes — getRoutesApi(router)

Dependencies — getDependenciesApi(router)

Guards — getLifecycleApi(router)

Plugin Infrastructure — getPluginApi(router)

For plugin authors, not for general use.

SSR / SSG


React / Preact / Solid / Vue / Svelte Integration

Provider

Hooks

Components

SSR Components & Hooks

SSR-feature subpath — @real-router/{adapter}/ssr. Symmetric across React/Preact/Solid/Vue/Svelte.

  • Lazy (Svelte only — dynamic component import)
  • Await — read deferred SSR data by key
  • Streamed — Suspense-style boundary
  • ClientOnly — server fallback → client children swap
  • ServerOnly — server children, removed after hydration
  • HttpStatusCode — render-time HTTP status declaration
  • HttpStatusProvider — provides sink to descendant <HttpStatusCode>
  • useDeferred — read deferred Promise by key

DOM Utilities

Patterns


Subscription Layer (@real-router/sources)


Reactive Streams (@real-router/rx)


Plugins

Browser Plugin

Navigation Plugin

Hash Plugin

Memory Plugin

Lifecycle Plugin

Preload Plugin

Logger Plugin

Persistent Params

SSR Data

RSC Server

Validation

Search Schema

Utilities


Reference

Types

Error Codes

Clone this wiki locally