Skip to main content
import { Link } from "@pylonsync/react";

<Link href="/hello">Hello</Link>
<Link> renders a plain <a> server-side, so it works with JavaScript off, on slow links, and during the brief moment before hydration completes. Once Pylon’s runtime is live, clicks get intercepted and Pylon does a client-side navigation instead of a full page reload.

What it does

PhaseBehavior
SSR / no JSRenders <a href data-pylon-link>...</a>. Same as a regular anchor.
In viewportIntersectionObserver fires __pylon.prefetch(href) — adds <link rel="prefetch" as="document"> for the URL + <link rel="modulepreload"> for the shared chunk.
Hover / touchstartSame prefetch logic, escalated for users who never saw the link in the viewport (touch devices, fast scrollers).
ClickpreventDefault(), fetch the new SSR HTML, dynamic-import the new route’s entry chunk (already preloaded), and re-render the React root in place.
Modifier keys / target=“_blank”Falls through to the browser’s default behavior — open in new tab, etc.
The React root persists across navigations, so any layout that’s shared between the old and new route keeps its instance. State, scroll position, video playback — all survive the nav.

API

interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
  /** Destination path. Same-origin paths get client-side nav; off-origin renders as plain <a>. */
  href: string;
  /** Default true. Set false to skip prefetch (long lists, pagination tails). */
  prefetch?: boolean;
  children?: React.ReactNode;
}
Any other anchor prop (className, target, rel, onClick, etc.) passes through.

Examples

Basic

import { Link } from "@pylonsync/react";

export default function Nav() {
  return (
    <nav className="flex gap-4">
      <Link href="/">Home</Link>
      <Link href="/dashboard">Dashboard</Link>
      <Link href="/settings">Settings</Link>
    </nav>
  );
}
A large paginated list with a “next page” link the user might never click:
<Link href={`/posts?page=${page + 1}`} prefetch={false}>
  Next →
</Link>

Open in a new tab

<Link href="/spec.pdf" target="_blank" rel="noopener">
  Spec (PDF)
</Link>
Modifier keys + middle-click also fall through automatically — no special handling needed.

Programmatic navigation

<Link> is the prop-based API. For imperative nav (after a form submit, post-login redirect, etc.), call the global runtime:
"use client";
window.__pylon?.navigate("/welcome");
The runtime is loaded as part of the shared chunk; window.__pylon is defined as soon as hydration completes. Use the ?. form to be safe on the first render.

How nav actually works

  1. User clicks a <Link>. The runtime’s delegated handler picks it off a[data-pylon-link] clicks.
  2. Runtime fetches the target URL with the standard Accept: text/html header. The server SSRs the new page just like a direct navigation would.
  3. Runtime parses the response and extracts the __PYLON_DATA__ JSON tag (component name, layouts, props).
  4. Runtime looks up the new component in the bundle manifest and dynamically imports its entry chunk.
  5. The entry chunk’s hydrate(component, Page, Layouts) populates the route cache without re-rendering (the cache is keyed on component path).
  6. Runtime calls root.render(buildTree(Page, Layouts, newProps)). React’s reconciler diffs against the existing tree — shared layouts get reused, the page subtree swaps.
  7. history.pushState, scroll to top, done.
If anything fails (fetch errored, response wasn’t HTML, manifest didn’t know the component), the runtime falls back to window.location.href = href so the browser handles it the old-fashioned way.

Differences from Next.js’s <Link>

Pylon <Link>Next.js <Link>
Prefetch triggerIntersectionObserver (256px rootMargin)IntersectionObserver
Hover escalationYes (once)Yes
Prefetch payloadHTML + shared chunkRSC payload + per-route JS
Nav modelRe-render in place, layouts preservedApp router preserves layouts the same way
scroll={false} propNot yetYes
Hash-only links (#section)Falls through to browserSmooth-scrolls in app router
The hash-link + scroll props are on the roadmap.