Navigation

Most navigation is a plain link.

JAF intercepts links to your own pages and swaps the content in place, so nothing reloads:

source
<script>
let userId = 123
</script>

<a href="/">Home</a>
<a href="/about">About</a>
<a href="/users/{userId}">My profile</a>

Links JAF leaves alone

Anything that is not an internal page navigation goes to the browser untouched: another origin, a mailto: or tel:, a target, a download, or a click with Cmd, Ctrl, Shift or Alt held.

Three attributes opt a link out by hand:

Attribute Why you would use it
rel="external" A path on this domain that another application serves. The request has to reach the server.
data-native The same thing, spelled JAF's way.
download Already left alone - the browser saves the file.

Links to other origins also get rel="noopener" added for you, so the page you open cannot reach back through window.opener.

You do not have to compare paths.

JAF puts aria-current="page" on every link whose href is the current route, and takes it off again when you leave. Style that:

<nav class="nav-demo">
  <a href="/docs/routing/files">Files</a>
  <a href="/docs/routing/navigation">Navigation</a>
  <a href="/docs/routing/guards">Guards</a>
</nav>

Add data-active-prefix to a link and it counts as current for everything below it too, which is what a top-level nav item usually wants: <a href="/docs" data-active-prefix> stays lit on /docs/routing/files.

Navigating from code

navigate() lives on the jafjs/router subpath and takes a path:

source
<script>
import { navigate } from 'jafjs/router'

async function save() {
  await saveDraft()
  navigate('/thanks')
}

function signIn() {
  // replace: the Back button skips the sign-in page
  navigate('/dashboard', { replace: true })
}
</script>

<button onclick="save()">Save</button>

Pass { replace: true } to overwrite the current history entry instead of adding one.

To go back, use the platform: history.back().

Passing data to the next page

Hand navigate() a data payload:

source
<script>
import { navigate } from 'jafjs/router'

function viewUser(user) {
  navigate('/users/' + user.id, { data: { user } })
}
</script>

<button onclick="viewUser({ id: 123, name: 'Alice' })">View Alice</button>

The destination reads it from window.route.data:

source
<!-- pages/users/[id].html -->
<script>
const user = window.route.data?.user
const userId = window.route.params.id
</script>

<h1>{user?.name}</h1>
<p>User {userId}</p>
The payload only lives in memory. It is not written to the URL or to history, so a reload or a shared link arrives with route.data undefined. Treat it as a shortcut, and make sure the page can still fetch what it needs from the URL.

Where you are now

window.route is reactive and holds path, params, query, hash, name and data:

source
<script>
// Visiting /users/123?tab=settings
const currentPath = window.route.path   // '/users/123'
const userId = window.route.params.id   // '123'
const tab = window.route.query.tab      // 'settings'
</script>

<p>{currentPath} - user {userId}, tab {tab}</p>
ui.page is deprecated. It was a second navigation API over this one and is removed in v0.2. ui.page.open(path, data) becomes navigate(path, { data }), and ui.page.close() becomes history.back(). See Overlays & UI State.