newX 1.3 — islands to disk, server-mode islands, image proxy

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.

just works
// No import needed — this already does client-side nav + hover prefetch:<a href="/docs/routing">Routing</a>

Opt individual links out with data attributes:

opt out
<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:

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.

createApp.ts / x.config.ts wiring
import { createImageProxyHandler } from "@thexjs/core";const imageProxy = createImageProxyHandler({  remoteHosts: ["stardance.hackclub.com"], // required allow-list — empty means requests are rejected});
usage
<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.

src/pages/_404.tsx
export default function NotFound() {  return <h1>Nothing here.</h1>;}