SSGOI

Qwik

Qwik keeps ownership of projected content and serializes state. Supply transition functions through a QRL factory and attach SSGOI to the layout that owns the routed slot.

Setup

Don't wrap the route <Slot /> in another component — forwarding it can keep routed content out of the live DOM during navigation.

// src/lib/ssgoi-config.ts
import { $ } from "@builder.io/qwik";
import { drill } from "@ssgoi/qwik/view-transitions";

export const config$ = $(() => ({
  transitions: [{ on: "/posts/**", except: "/posts", transition: drill() }],
}));

// src/routes/layout.tsx
import { Slot, component$, useSignal } from "@builder.io/qwik";
import { useSsgoi } from "@ssgoi/qwik";
import { config$ } from "../lib/ssgoi-config";

export default component$(() => {
  const root = useSignal<HTMLElement>();
  useSsgoi(root, { config$ });

  return (
    <main ref={root} class="relative z-0 min-h-dvh overflow-x-clip">
      <Slot />
    </main>
  );
});

// src/routes/posts/index.tsx — each routed page marks its own root
import { component$ } from "@builder.io/qwik";

export default component$(() => (
  <article data-ssgoi-transition="/posts">{/* page */}</article>
));

Qwik City

Experimental API

The computed boundary helper reads Qwik City’s location. The page keeps ownership of its DOM and slots; apply the returned id and key to its own root.

Mark the page root

Call the hook in a Qwik City page or layout, not root.tsx. An explicit key replaces the page root when a parameterized route is reused. Query and hash changes keep the same key.

import { component$ } from "@builder.io/qwik";
import { useSsgoiRouteBoundary } from "@ssgoi/qwik/qwik-city";

export default component$(() => {
  const boundary = useSsgoiRouteBoundary();
  return (
    <article key={boundary.value.key} data-ssgoi-transition={boundary.value.id}>
      {/* Page content */}
    </article>
  );
});

Persistent layouts

Pass a stable route key to useSsgoiRouteBoundary("shell") for an outer shell, and retain separately keyed page roots below it. The helper does not wrap or move Slot content.

The helpers connect your router to the common implementation. Route boundaries explains how to connect another router directly. Transitions and route rules apply across the web frameworks.