SSR

glyphflow renders on the server without a real window or document. The icon arrives already painted in the HTML; the animation starts once the browser hydrates.

What happens on each side

MomentWhat you see
Server renderThe full <svg>, with its geometry and its aria-hidden. No animation: there's no WAAPI in Node.
After hydrationThe same SVG, now alive. The trigger starts working.

Nothing to configure

No afterNextRender, no isPlatformBrowser guard, no deferred import of the component. It works with whatever SSR config you already have.

How it's verified

With a smoke test that runs in real Node, not jsdom — and that's the point: jsdom defines window, so a test running there wouldn't prove anything. The script starts by deliberately failing if it detects window:

if (typeof window !== 'undefined') {
  throw new Error(
    'This smoke test must run without a global `window` — if it exists, it proves nothing.',
  );
}

Then it renders with renderApplication from @angular/platform-server and demands two things from the resulting HTML: that there's an <svg>, and that it carries the decorative icon's aria-hidden="true". Runs in CI on every commit (npm run test:ssr).

The second check isn't decoration. A render that "doesn't throw" but returns empty HTML passes any test that only checks for an exception — that's why the test asserts on content, not on the absence of an error.

Morph on the server

<gf-icon-morph> falls through the same path as the client's first render: it paints the static icon. Morphing "from nothing" doesn't exist, and on the server there's no previous value to morph from either. You see the right icon; the transition waits for the browser.