Guides
Client Navigation & Images
Every plain <a> tag on an x site already navigates client-side, with no router setup required. This page covers that behavior, the <Link> convenience component, the built-in remote image proxy, and the two error surfaces (dev overlay, 404 page).
Client-side navigation, by default
Every rendered page inlines a small navigation script (CLIENT_NAV_SCRIPT). It intercepts clicks on same-origin <a href> elements, fetches the destination page, and swaps the page content in place instead of doing a full browser navigation, so you get SPA-style transitions without adding a router or wrapping links in anything. It also prefetches on hover/focus and handles back/forward via popstate.
// No import needed — this already does client-side nav + hover prefetch:<a href="/docs/routing">Routing</a>Opt individual links out with data attributes:
<a href="/legacy" data-no-nav>Full page load</a><a href="/heavy-page" data-no-prefetch>No hover prefetch, still client nav</a>Links are skipped automatically if they cross origins, open a new tab (target), carry a download attribute, or use a #/mailto:/tel: scheme. Those always behave like normal anchors.
The <Link> component
<Link> is a typed wrapper around the same behavior above. Use it when you want the opt-out props to be type-checked instead of stringly-typed data attributes:
import { Link } from "@thexjs/core";<Link href="/docs">Docs</Link>// Same opt-outs, as real props:<Link href="/legacy" clientNav={false}>Full page load</Link><Link href="/heavy-page" prefetch={false}>No prefetch</Link>Remote image proxy
createImageProxyHandler mounts a GET /_x/image route that fetches an allow-listed remote image server-side and streams it back from your own origin. The browser never makes a cross-origin image request, so a strict img-src 'self' CSP (see Security) still works even with remote images. This page's own Stardance badge is proxied through it right now.
import { createImageProxyHandler } from "@thexjs/core";const imageProxy = createImageProxyHandler({ remoteHosts: ["stardance.hackclub.com"], // required allow-list — empty means requests are rejected});<img src={`/_x/image?url=${encodeURIComponent("https://stardance.hackclub.com/logo.png")}`} /> >It's a proxy, not an optimizer. No resizing or format conversion happens. Only hosts in remoteHosts are ever fetched (this is what prevents the route from becoming an open SSRF relay), only a fixed set of image content types are allowed through, and successful responses are served with a one-day, immutable Cache-Control header.
Dev error overlay
When a loader, page, or API route throws during x dev, renderErrorOverlay renders a full-screen overlay with the error message and stack trace, instead of a bare 500 response. It's dev-only: production builds never ship the overlay, they return a plain error response.
404 handling
Drop a src/pages/_404.tsx to customize the site-wide not-found page. If you don't provide one, x falls back to DefaultNotFound, a minimal built-in page, so every project has a sane 404 without extra setup.
export default function NotFound() { return <h1>Nothing here.</h1>;}