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
| Moment | What you see |
|---|---|
| Server render | The full <svg>, with its geometry and its aria-hidden. No animation: there's no WAAPI in Node. |
| After hydration | The 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.