Skip to content

x-interact:navigate ​

x-interact:navigate requests a normal CakePHP page and replaces the current page content without restarting Alpine. It works inside and outside islands.

html
<a href="/articles" x-interact:navigate>Articles</a>
php
<?= $this->Html->link('Articles', '/articles', ['x-interact:navigate' => true]) ?>

The helper example uses CakePHP's HtmlHelper for links. Both examples keep a real href for native navigation.

Page requests ​

The destination runs through its ordinary GET route, middleware, controller, authorization, and template. Return a complete HTML document with the Interact helper loaded and the layout's script block rendered, as in installation. No navigation endpoint or client router is required.

Page-owned islands mount fresh. Use x-interact:persist to retain explicit layout regions and compatible embedded islands.

Modified clicks, downloads, external links, links targeting another browsing context, and same-page fragments keep native behavior. Forms are not intercepted. Failed assets, unsupported documents, changed session or security policy, and incompatible deployments fall back to native navigation. Actions are never automatically replayed.

Prefetching ​

By default, an unmodified primary mouse-button press starts fetching the destination. Releasing the button over the link activates the visit; pressing alone never changes the page. Modified clicks, downloads, external links, and links targeting another browsing context keep their native behavior.

Use .hover to start earlier:

html
<a href="/articles" x-interact:navigate.hover>Articles</a>

.hover starts fetching after 60 ms of hover or keyboard focus. Leaving before that delay cancels the pending prefetch. Prefetched HTML remains inert: no scripts, islands, polling, uploads, or deferred mounts initialize.

Mouse-down and its click share one navigation attempt. The click uses that attempt's response whether it is still downloading or has already finished, including responses with no-store, no-cache, or no explicit freshness. The result stays in memory only for that press and is consumed once. Releasing outside the link, dragging it, keyboard input, losing window focus, a changed link destination, or removing the link abandons the attempt. A mouse-up without a handled click also releases it.

Hover, focus, mouse-down, and click share the same navigation attempt while the link remains hovered or focused. The click consumes the response once, including completed responses with no-store, no-cache, or no explicit freshness. Mouse-down takes ownership of the attempt until click or abandonment; focus following mouse-down does not start another request.

Leaving or blurring the link, losing window focus, changing its destination, or removing it releases an unused hover attempt. After abandonment, completed responses remain available only when their Cache-Control permits explicit freshness, for at most 30 seconds. Uncached responses and abandoned pending requests are released. Navigation and island requests invalidate unused prefetched pages.

Use .no-prefetch to disable mouse-down and hover prefetching for a link:

html
<a href="/reports" x-interact:navigate.no-prefetch>Reports</a>
php
<?= $this->Html->link('Reports', '/reports', ['x-interact:navigate.no-prefetch' => true]) ?>

The link still uses enhanced navigation on click or keyboard activation. .no-prefetch takes precedence over .hover in either modifier order. Prefetching adds GET requests even when a user abandons a click; destination GET routes must remain safe.

Scroll and focus ​

New visits scroll to the top, or to the fragment target. Back and Forward fetch fresh HTML and restore the history entry's page scroll. Same-page history created by URL bindings continues restoring island properties without replacing the document.

html
<a href="/articles?page=2" x-interact:navigate.preserve-scroll>Next page</a>

.preserve-scroll retains the page's current scroll on that visit. Scrollable regions inside retained DOM keep both scroll axes automatically. Retained focused controls keep focus and selection; otherwise the destination's autofocus control or main content receives focus.

Matching navigation links automatically receive aria-current="page", including links inside persistent regions. Matching uses the same origin and exact path, ignores query strings and fragments, and normalizes trailing slashes.

css
nav a[aria-current='page'] {
  font-weight: bold;
}

Classes and styling remain application-owned. No additional active-link directive is required.

Active trails ​

Add .trail to mark a section link on its own page and descendant paths:

html
<a href="/articles" x-interact:navigate.trail>Articles</a>
php
<?= $this->Html->link('Articles', '/articles', ['x-interact:navigate.trail' => true]) ?>

Interact manages the boolean data-interact-active-trail attribute; do not set it yourself. Links without .trail keep exact-page matching and receive no trail attribute. aria-current="page" continues to identify only exact matches.

For the link above:

Current patharia-current="page"data-interact-active-trail
/articlesPresentPresent
/articles/42/editAbsentPresent
/articles-archiveAbsentAbsent
css
nav a[data-interact-active-trail] {
  font-weight: bold;
}

nav a[aria-current='page'] {
  text-decoration: underline;
}

Trail matching requires the same origin and complete, case-sensitive path segments. It ignores query strings and fragments and normalizes trailing slashes. A link to / matches only the root page. Matching follows URL ancestry, independently of CakePHP route names.

Both attributes update when links initialize, destinations change, or the current URL changes, including Back/Forward and links inside persistent regions. Combine .trail with .hover and .preserve-scroll in any order.

Loading feedback ​

The Alpine store $store.interactNavigation describes page visits independently of any island's $server request activity. Interact ships no indicator markup, CSS file, or injected styles.

Use Alpine's x-show and attribute bindings to present this activity, just as with island request feedback.

html
<span
  x-data
  x-show="$store.interactNavigation.loading({ delay: 300 })"
  x-cloak
  role="status"
>
  Loading page…
</span>
MemberBehavior
pendingTrue immediately during a visit
loading()True after 200 ms of continuous activity
loading({ delay: 300 })Use an indicator-specific delay in milliseconds

The default delay follows JavaScript configuration. Delay accepts whole milliseconds from 0 to 60,000. Activity includes fetching, required assets, replacement, and initialization. Prefetching alone does not show feedback. Completion, cancellation, and failures clear timers; older requests cannot hide feedback for a newer visit. Use your application's existing x-cloak rule.

See the tested navigation example for an application-styled top bar.

Document events ​

These standard DOM events are dispatched on document and can also be observed with Alpine's .document event modifier.

EventTiming
interact:navigateBefore starting a visit; cancelable
interact:navigatingImmediately before replacing page content
interact:navigatedAfter Alpine initialization, focus, and scroll; also once after initial startup
interact:navigation-errorBefore a failed visit falls back to native navigation

event.detail.url is the destination URL object. event.detail.history identifies a cross-page Back/Forward visit. The error event additionally exposes cause for diagnostics.

js
document.addEventListener('interact:navigate', (event) => {
  if (hasUnsavedChanges() && !confirm('Leave this page?')) {
    event.preventDefault();
  }
});

document.addEventListener('interact:navigated', () => {
  initializePageIntegrations();
});

The functions above are application-supplied. Global listeners survive page visits; register them once. Use Alpine cleanup for page-local widgets. DOMContentLoaded and alpine:init do not fire again.

Head elements and scripts ​

Navigation reconciles the destination's head in declaration order. Equivalent elements are reused one-to-one, including repeated metadata. Obsolete page stylesheets, inline styles, canonical links, and metadata are removed. Stylesheets and inline styles keep their interleaved cascade order. Head elements inserted later by application JavaScript remain after server-declared elements.

New required stylesheets download concurrently while the current page remains styled. Only the winning visit activates them and replaces the head and body. Disabled and alternate stylesheets retain their native attributes. Failed or superseded visits remove staged styles without removing the current page's styles.

External scripts execute once per browser document, before incoming Alpine initialization. Removing a script tag cannot undo its code or listeners. Register late-loaded Alpine components immediately when Alpine already exists, rather than waiting for alpine:init. Alpine and Interact bootstrap scripts are not rerun. Data scripts such as application/json remain inert. Executable inline scripts, import maps, <base>, and http-equiv metadata require a native visit.

Use x-interact:asset to reload on changes to versioned application bundles or explicitly retain a shared stylesheet. Unmarked page styles are removed when absent from the destination.

CSP nonces ​

Nonce-only CSP rotation supports enhanced navigation. Interact maps nonce values advertised by the destination's CSP response headers to the active document's corresponding script/style nonces. Unrecognized values are not granted a nonce. The original browser policy remains active, and this does not enable executable inline scripts.

Changes to policy directives, sources, nonce relationships, session identity, or runtime compatibility require a native visit. The same checks apply to prefetched responses and history restoration. See security.

Interact's document middleware records compatibility after application middleware has produced the response. Keep it outside middleware that changes document security headers. Headers added by later plugin or infrastructure middleware are not covered by its fingerprint; place the document middleware outside that middleware too, or use native navigation for those pages. Nonce markers must agree with the fetched response's actual CSP headers.

Set Interact.navigationVersion when application-owned assets change incompatibly without changing a tracked head asset. The packaged runtime fingerprint is tracked automatically only when the helper includes that runtime. See redirects.

Options ​

ModifierBehavior
.hoverPrefetch after 60 ms of hover or focus
.no-prefetchDisable mouse-down and hover prefetching while retaining enhanced visits
.preserve-scrollRetain current page scroll for the visit
.trailMark the current page and URL ancestors with data-interact-active-trail

The directive accepts no expression. Combine modifiers when needed.