Dynamic Routes
Brackets in a filename capture a piece of the URL.
Name the file [id].html and every
/users/<anything> lands on it.
pages/
└── users/
└── [id].html → /users/:id
The captured value arrives on window.route.params:
<!-- pages/users/[id].html -->
<script>
const userId = window.route.params.id
</script>
<p>User ID: {userId}</p>
Visit /users/123 and userId is the string
"123".
Params are always strings - wrap one in Number(...) if you need a
number.
Several in one path
Each bracketed segment becomes its own param:
Select a file to see what it is for
<!-- pages/blog/[year]/[month]/[slug].html -->
<script>
const { year, month, slug } = window.route.params
</script>
<h1>{slug}</h1>
<p>Published: {month}/{year}</p>
A named file wins
Static routes are matched before dynamic ones:
Select a file to see what it is for
So /users/me loads me.html and
/users/42 loads [id].html.
You never have to order anything yourself.
Linking to one
Put the real value in the href:
<script>
let users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
</script>
<ul>
{users.map(user => (
<li>
<a href="/users/{user.id}">{user.name}</a>
</li>
))}
</ul>
[id].html gives
you params.id, [slug].html gives you
params.slug. Brackets keep their capitals, so
[userId].html is params.userId.
What goes in the brackets
A letter or underscore, then letters, digits or underscores - the same shape as
a JavaScript variable, because the name becomes params.name and a
generated type.
[id], [userId] and [post_id] route.
[user-id], [a.b], [123] and
[$id] do not: the build warns, naming the file, and the page
routes at its literal path instead.
[id].html answers
/users/42 and never /users/42/edit. The Next.js and
Nuxt spelling [...slug].html is not a JAF route - the build says
so rather than leaving you with a 404 that looks like a config problem. Route
the levels you actually have: docs/[section]/[page].html.
A param the URL cannot decode
/users/%zz is not valid percent-encoding. The route still matches
and params.id holds the literal text "%zz" - the same
answer a query param gives - so a hand-edited or truncated link cannot take the
page down.
Dev builds warn, naming the reader and the segment.
Related
- Navigation - reading the current route, navigating from code
- File-Based Routing - how files become URLs