Skip to content
Vidact

Vidact Start

Navigation

Move between routes without a page reload using Link and the client's navigate function.

Vidact Start renders every route on the server, but once the page has hydrated, moving between routes happens in the browser. The server sends only the new loader data, and the client swaps the route content in place.

Prefetching

A Link starts loading its route before you click it. When the pointer rests on a link for 50 ms, or the link receives keyboard focus, Start requests the route's loader data and downloads its code. Pressing the link starts the same work, which still saves the gap between press and release. The click then reuses the prefetched data instead of waiting on the network.

A prefetched snapshot backs one navigation and expires after 30 seconds, so loader data is never older than that. When the browser has data saver turned on, hover and focus stop prefetching and only a press does.

Links whose loaders are expensive or have side effects can opt out:

tsx
<Link href="/reports/export" prefetch="none">Export</Link>

To prefetch from code, for example when a menu opens, call client.prefetch:

ts
await client.prefetch('/products/42')

Programmatic navigation

hydrateStart returns a client with a navigate method. Keep a reference to it where your code needs it, for example in a module-level store.

src/client.ts
import { hydrateStart } from '@vidact/start/client'import { routeManifest } from 'virtual:vidact-start/routes'export const client = await hydrateStart({ manifest: routeManifest })
ts
await client.navigate('/products/42')await client.navigate('/login', { replace: true, scroll: false })

navigate resolves to true when the navigation completed and false when it was cancelled by a newer navigation or the server declined. It accepts a string or a URL.

What a navigation does

  1. The client requests the target URL with a header asking for a snapshot rather than a document, unless a fresh prefetch already holds one. The matched route modules download at the same time.
  2. The server runs the matched loaders and responds with serialized loader data.
  3. The client updates the props of unchanged routes and replaces the portion of the route tree that changed.
  4. Browser history is updated. Unless scroll: false, the window scrolls to the destination fragment or the top of the page.

Navigations are cancellable: clicking two links quickly discards the first response. Back and forward buttons restore previous entries the same way.

State across navigations

Start retains the common prefix of matched route components. Moving between two pages under the same layout preserves that layout's DOM, state, refs, and effects. Its loaderData, params, requestUrl, and children props update for the destination. Changes to parameters or query strings can also keep the same page component mounted when the matched route stays the same.

Components below the first changed route are replaced. For example, navigating from /blog/first to /blog/second keeps blog/$slug.tsx mounted and updates its props. Navigating from /blog/first to /about disposes the blog page and layout. Use an external store for state that must outlive the route that owns it.

Scroll and focus

Links with a fragment, such as /docs/learn/state#initial-values, scroll to that element after navigation. Other destinations scroll to the top. Pass scroll: false to navigate when you are updating a filter or a tab and want the viewport to stay put. Start does not move focus; move it yourself in an effect if the new content needs it for accessibility.