-
-
Notifications
You must be signed in to change notification settings - Fork 0
HttpStatusCode
-
Name:
HttpStatusCode -
Purpose: Declare the HTTP response status from inside the rendered tree. Writes
codeto the nearest<HttpStatusProvider>'s sink during component init; the SSR entry readssink.codeafterawait render()and applies it to the response. -
When to use: Render-time status decisions — primarily 404 (catch-all routes), 410 (gone resources), 451 (legal-block), or any status driven by the rendered route content rather than a loader. Loader-driven errors (
LoaderNotFound→ 404,LoaderRedirect→ 30x) keep working viassr-data-pluginwithout this component. -
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. Semantics identical across adapters.
<!-- routes/NotFound.svelte -->
<script lang="ts">
import { HttpStatusCode } from "@real-router/svelte/ssr";
</script>
<HttpStatusCode code={404} />
<h1>Page Not Found</h1>
<p>Sorry, that URL doesn't match any route.</p>On the server, mounting this component sets sink.code = 404 during init. The SSR entry reads sink.code after await render() and calls response.status(404).send(html).
On the client, <HttpStatusCode> is a silent no-op (no <HttpStatusProvider> mounted → getContext returns undefined → no write, no DOM, no warning).
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
code |
number |
Yes | — | HTTP status code to apply. Common values: 404, 410, 451, 503. Valid range: 100-999 (per Node res.end()). |
The component reads getContext<HttpStatusSink | undefined>(HTTP_STATUS_KEY) once during init. If a provider is mounted, it writes sink.code = code synchronously and renders nothing. The // svelte-ignore state_referenced_locally directive intentionally allows the one-time write — replacing code mid-render isn't supported.
When multiple <HttpStatusCode /> instances mount in the same render pass, the last one to run wins. Component init order follows template order:
<HttpStatusCode code={200} />
<HttpStatusCode code={404} /> <!-- This wins. -->Svelte 5 stable does NOT chunk-flush {#await} blocks — the server emits the full HTML in one response, including any <HttpStatusCode /> writes. The sink is therefore always written by the time await render(App, { props }) resolves. No ordering surprises with <Streamed> / <Await> boundaries.
The component checks for the sink via getContext and SKIPS the write when the sink is undefined. This is the client-side runtime path — <HttpStatusCode> renders inside the same component tree post-hydration, but with no provider mounted, the getContext lookup returns undefined and the component becomes a silent no-op. No DOM, no warning, no hydration mismatch.
Svelte 5's hydration walker tolerates {#if}-branch asymmetry between server and client (verified by examples/web/svelte/ssr-examples/ssr/). The typical pattern is to mount <HttpStatusProvider> only on the server — Svelte hydrates fine without it. This contrasts with Vue/Solid which require symmetric provider mounting.
<!-- routes/NotFound.svelte (matched by route name "@@notFound" or path "/*") -->
<script lang="ts">
import { HttpStatusCode } from "@real-router/svelte/ssr";
</script>
<HttpStatusCode code={404} />
<main>
<h1>404 — Not Found</h1>
<a href="/">Back to home</a>
</main><script lang="ts">
import { HttpStatusCode } from "@real-router/svelte/ssr";
import { useRoute } from "@real-router/svelte";
const { route } = useRoute();
const product = route.current.context.data?.product;
const isDeleted = product?.status === "deleted";
</script>
{#if isDeleted}
<HttpStatusCode code={410} />
<h1>This product is no longer available</h1>
{:else}
<ProductPage {product} />
{/if}<script lang="ts">
import { HttpStatusCode } from "@real-router/svelte/ssr";
export let blocked: boolean;
</script>
{#if blocked}
<HttpStatusCode code={451} />
<h1>Content unavailable in your region</h1>
{/if}{#if maintenance.active}
<HttpStatusCode code={503} />
<MaintenanceBanner endsAt={maintenance.endsAt} />
{/if}To make the status take effect, the SSR entry must:
- Create a sink with
createHttpStatusSink(). - Wrap the rendered tree in
<HttpStatusProvider sink={...}>. - Read
sink.codeafterawait render().
// entry-server.ts
import { render } from "svelte/server";
import App from "./App.svelte";
import { createHttpStatusSink } from "@real-router/svelte/ssr";
export async function handler(req, res) {
const sink = createHttpStatusSink();
const router = await setupRouter(req.url);
const output = await render(App, { props: { router, sink } });
res.status(sink.code ?? 200).send(output.body);
}<!-- App.svelte -->
<script lang="ts">
import { HttpStatusProvider } from "@real-router/svelte/ssr";
import RootRoute from "./routes/Root.svelte";
let { router, sink } = $props();
</script>
{#if sink}
<HttpStatusProvider {sink}>
{#snippet children()}
<RootRoute {router} />
{/snippet}
</HttpStatusProvider>
{:else}
<RootRoute {router} />
{/if}The {#if sink} makes the provider server-only. Svelte 5's hydration walker accepts the asymmetry between server (provider present) and client (provider absent).
-
No provider → silent no-op. Without an
<HttpStatusProvider>somewhere up the tree,<HttpStatusCode />does nothing. Verify provider wiring if status isn't applied. -
Last write wins. Multiple
<HttpStatusCode />in the same render set the sink in template order; the last one wins. Doesn't usually matter (typical case: one component per route) but worth knowing for conditional renders. -
Valid code range. Node's
res.end()throws "Invalid status code" onNaN,0, negative numbers, or values> 999. Pass a real HTTP status integer. -
No mid-render updates. The sink is written once at component init. Changing
codereactively doesn't update the sink — remount the component (via{#key}) to push a new value. -
Loader-driven 404/30x is preferred when the data dictates the status. Use
ssr-data-plugin'sLoaderNotFound/LoaderRedirectfor those cases;<HttpStatusCode>is for render-time decisions only.
-
<HttpStatusProvider>must wrap the tree (typically server-only). -
getContextfrom Svelte —<HttpStatusCode>calls it during init. -
createHttpStatusSink()from@real-router/svelte/ssrto construct the sink in the SSR entry.
- HttpStatusProvider — context provider that wires the sink
- Svelte Integration Guide — overview of the SSR surface
- Server-Side Rendering — full SSR setup guide
-
@real-router/ssr-data-plugin— for loader-drivenLoaderNotFound/LoaderRedirect
- View-Agnostic Design
- Core Concepts
- Navigation Lifecycle
- Guards
- Plugin Architecture
- Hash Fragment Support
- Accessibility (A11y)
- Server-Side Rendering
- Data Loading
- Streaming SSR
- SSR Cancellation
- RSC Integration
- Testing
- Glossary
Tree-shakeable functions — import only what you need.
- add (addRoute)
- remove (removeRoute)
- replace (replaceRoutes)
- clear (clearRoutes)
- get (getRoute)
- has (hasRoute)
- update (updateRoute)
- get (getDependency)
- getAll (getDependencies)
- set (setDependency)
- setAll (setDependencies)
- has (hasDependency)
- remove (removeDependency)
- reset (resetDependencies)
For plugin authors, not for general use.
- makeState
- buildState
- buildNavigationState
- forwardState
- getForwardState
- setForwardState
- matchPath
- setRootPath
- getRootPath
- navigateToState
- addEventListener
- getRouteConfig
- getOptions
- addBuildPathInterceptor
- extendRouter
- getTree
- React Integration Guide
- Preact Integration Guide
- Solid Integration Guide
- Vue Integration Guide
- Svelte Integration Guide
- Ink (Terminal UI) Integration Guide
- Desktop (Electron, Tauri) Integration Guide
- useRouter
- useRoute
- useRouteNode
- useNavigator
- useRouteUtils
- useRouterTransition
- useRouteExit
- useRouteEnter
- useRouteStore (Solid only)
- useRouteNodeStore (Solid only)
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