re-frame.routing¶
Routes are data. You register a route with a path and a metadata map (:params, :query, :on-match, :on-error, :can-leave, …). URL changes become events. The current route lives in the frame's runtime-db at [:rf.runtime/routing :current] and is read via the :rf/route sub. Navigation is dispatching an event.
This namespace is the public boot point and façade for the routing artefact. Requiring it wires every routing event, fx, cofx, and sub. The reg-route macro is published on the re-frame.core facade. The rest of the surface lives here:
- URL helpers
- registry introspection
- scroll restoration
- URL strategies
- the browser URL-listener boot seam
- the multi-frame URL-ownership resolver
For motivation and narrative, see the Routing guide.
Throughout, rf is the re-frame.core facade alias ([re-frame.core :as rf]). The reg-route macro and the route-link view live on that facade.
Route registration¶
reg-route¶
- Kind: function (
re-frame.corepublishes the source-coord-capturingreg-routemacro; this namespace'sreg-routeis the equivalent plain fn) - Signature:
-
Description: Register a route as data.
-
id— keyword dispatched against later ([:rf.route/navigate :route/cart]). metadata— map of match events and guards (keys below).path— the URL shape; colon-prefixed segments capture into:params.
Throws :rf.error/route-bad-metadata when metadata:
- is not a map,
- carries
:path(the path pattern belongs in the third slot), or - carries a bare (unqualified) key outside the reserved set below. Namespaced keys (
:myapp/analytics-id) always pass.
Emits :rf.warning/route-shadowed-by-equal-score when an already-registered route has an equal structural rank and the two patterns can match a common URL (/a/:x vs /a/:y warns; /x/:id vs /y/:slug doesn't — they tie structurally but never compete for a URL). The earlier registration wins the tiebreak at match time, so the new route is the shadowed one: the warning's tags name it under :route-id, the existing winner under :shadowed-by, and the tied structural tuple under :rank. Emits :rf.route/registered on first-time registration.
A minimal route¶
Colon-prefixed path segments capture into :params. :on-match is the event vector (or vector of event vectors) dispatched when the route activates. Everything else is optional.
Reserved metadata keys¶
| Key | Notes |
|---|---|
:doc |
Free-form description; pair tools read this. |
:params |
Schemas for path segments. |
:query |
Schemas for query-string keys. |
:query-defaults |
Default values for query keys absent from the URL. |
:query-retain |
Keys to preserve across navigations to other routes. |
:tags |
Free-form classification, e.g. #{:auth-required :admin-only :public}. |
:parent |
Another route id; builds a chain readable via :rf.route/chain. |
:on-match |
Event vector(s) to dispatch when the route activates. |
:on-error |
Event vector dispatched if any :on-match event errors. |
:can-leave |
Guard sub-query run before leaving the route. Closed boolean contract: true allows, false blocks. Any non-boolean also blocks and emits :rf.error/can-leave-non-boolean. The name reads positively, so false means "can NOT leave". The sub receives the pending target as an argument. See Routing → Blocking a navigation. |
:can-enter |
Guard sub-query run before entering the route (the auth-gate mirror of :can-leave). Closed boolean contract: true allows entry, false blocks. Any non-boolean also blocks and emits :rf.error/can-enter-non-boolean. On a block the runtime dispatches :rf.route/entry-blocked. See Routing → Guarding entry. |
:scroll |
Scroll-restoration behaviour for this route. |
:sensitive |
Slice paths (projection-relative, e.g. [:query :token]) redacted at egress while the route is active. See Routing → Keeping tokens off the wire. |
:large |
Slice paths kept off the wire at egress (a size marker ships instead of the value). |
Two cross-feature bare keys are also accepted:
:head— SSR's head-metadata contract. It is always in the accepted set.:resources— the Resources artefact's route integration, late-bound via the:routing/extra-route-keyshook. In an app without the Resources artefact,:resourcesis rejected like any other unknown bare key.
Canonical detail in The metadata map, in full.
clear-route¶
- Kind: function
- Signature:
- Description: Remove a registered route. Emits
:rf.route/cleared(symmetric with:rf.flow/cleared) so tools subscribing to route lifecycle observe the removal. No-op whenidwas not registered.
reset-counters!¶
- Kind: function
- Signature:
- Description: Test-time helper. Resets the route-registration index counter to zero so the registration-order tie-breaker in route ranking is deterministic across fixture runs.
URL and route matching¶
The URL ↔ route mapping is a prism. match-url reads a URL into route data. route-url renders route data back into a URL. match-url(route-url(...)) round-trips the canonical route data. Both functions are pure and JVM-runnable.
match-url¶
- Kind: function
- Signature:
-
Description: Match a URL to route data. Pure; JVM-runnable.
-
Returns
nilwhen no route matches. Also fails closed tonilon malformed percent-encoding anywhere in the URL. - When the route declares
:params/:queryschemas and the parsed values fail them,:validation-failed?istrueand the explanation rides under:validation-error. - Query keys the route declares (via
:query/:query-defaults/:query-retain) come back as keyword keys, in a deterministic canonical order. Undeclared keys stay strings. - Example:
route-url¶
- Kind: function
- Signature:
-
Description: Render a route to a URL — the inverse of
match-url. Pure; JVM-runnable. -
The 4-arity appends
#fragmentwhenfragmentis a non-empty string (nil/""append nothing). - Nil-valued query keys are silently elided. A nil required path param is an error.
- Query keys are emitted percent-encoded, in a deterministic canonical order.
Throws:
- :rf.error/no-such-route — route-id not registered.
- :rf.error/missing-route-param — a required path segment's param is nil or absent.
- :rf.error/route-url-validation — path-params / query-params fail the route's :params / :query schemas.
- :rf.error/route-url-non-edn-value — non-EDN param/query values or a non-string fragment.
- Example:
;; with (rf/reg-route :user/show {} "/users/:id") registered:
(routing/route-url :user/show {:id 42}) ;; => "/users/42"
;; query params are appended and percent-encoded:
(routing/route-url :search {} {:q "hello world"}) ;; => "/search?q=hello%20world"
malformed-url?¶
- Kind: function
- Signature:
- Description:
truewhen any percent-encoded portion ofurlis malformed — a non-empty path segment, a query key or value, or the#fragment. The check is purely lexical; no route table is consulted.
The :rf.route/transitioned / :rf.route/handle-url-change handlers use it to tell two cases apart: a plain route miss ({:url url}) and a malformed URL that failed closed ({:url url :reason :malformed-url}). Both cases end at :rf.route/not-found. The structured :reason lets per-route error UIs and SSR projections branch on the cause.
current-url¶
- Kind: function
- Signature:
- Description: Read the current browser URL as an app-relative string (
pathname + search + hash). Returns"/"when nowindow.locationis available (JVM / SSR / Node). This is the history strategy's:decode. A hash app's listener decodes through its own strategy and never calls this directly. It is public so apps that wire their own history listener can recover the same projection the framework's listener uses.
Introspection and slice access¶
This is the read-side surface over the route registry and the live route slice. The static accessors answer "which routes are registered, and what is route X's spec?". The live readers expose the per-frame slice. The *-algebra-view helpers lower routes into the shared derivation/process-algebra node shape, so a tool can show subscriptions, flows, resources, route facts, and machine selectors as one family.
route-ids¶
- Kind: function
- Signature:
- Description: Return a vector of every registered route id. This is the static-registry "enumerate" half of routing introspection; the live per-frame slice is read through the
:rf.route/*subs instead. Mirrors the sibling accessors:resource-idsfor resources,machinesfor machines. - Example:
route-meta¶
- Kind: function
- Signature:
- Description: Return the metadata map registered for
route-id, ornilif no route is registered under that id. The map carries the:pathpattern,:on-match,:params,:query,:scroll, and:can-leave. It also carries the computed:rf.route/rank/:rf.route/compiled/ coercion tables and the source coords. Mirrors the sibling accessors:resource-metafor resources,machine-metafor machines.
route-algebra-view¶
- Kind: function (JVM convenience alias; CLJS callers use
re-frame.routing.tooling/route-algebra-view) - Signature:
- Description: The STATIC derivation/process-algebra view of every registered route. It is pure data over the
:routeregistrar kind — no app-db, no runtime-db, no live slice. The zero-arity form returns the map for every route ({}when none). The one-arity form returns one node, ornil. JVM-runnable; consumed by Xray and the conformance fixtures. There is nore-frame.corefacade export.
Each route lowers to a normalized node carrying:
- :id :rf/route — the route FACT identity (every route materializes the one route slice; the per-route registration id is under :source-form).
- :kind :process, :refinement :route-fact.
- :source-form {:kind :reg-route :id <route-id>}.
- :inputs — the route-transition inputs (:rf.route/navigate / :rf.route/transitioned / :rf.route/handle-url-change).
- :output [:runtime [:rf.runtime/routing :current]], :storage :runtime-db.
- :evaluation :on-route, :lifecycle :frame, :materialized? true.
- :resource-edges — only when the route declares :resources.
route-slice-algebra-view¶
- Kind: function (JVM convenience alias; CLJS callers use
re-frame.routing.tooling/route-slice-algebra-view) - Signature:
- Description: The LIVE counterpart to
route-algebra-view. It reads the route fact materialized in a frame's runtime-db at[:rf.runtime/routing :current]— the concrete matched route, with its params, query, transition state, and nav-token. Returns a single:route-factnode. Returnsnilwhen the frame is missing or destroyed, or when no navigation has committed yet (so no route has been materialized). The node carries the same fixed classifications as the static node, plus:route-id,:params,:query,:transition,:nav-token, and:owner[:route <route-id> <nav-token>]. Runs on both CLJS and the JVM (a single runtime-db container deref).
route-sub-fn¶
- Kind: function
- Signature:
- Description: The layer-1 sub fn behind
:rf/route. It reads the route slice from[:rf.runtime/routing :current]. Exposed publicly so external callers (smoke tests, tooling) can read the slice without re-deriving the path.
Reading the route and the pending-nav slot¶
You read the route slice and the pending-navigation slot with ordinary subscribe calls naming their framework sub vectors. There is no named-read-sugar fn — a runtime-db framework read is a subscription vector, one grammar. Both are per-frame singletons, so no id argument is needed. To read an explicit frame (say, a non-default url-bound one), use subscribe's {:frame <target>} opts form.
(:route-id @(rf/subscribe [:rf/route])) ;; the active route id, or nil pre-navigation
;; show an "unsaved changes?" prompt only while a navigation is blocked
(when-let [pending @(rf/subscribe [:rf/pending-navigation])]
[confirm-leave-dialog pending])
The :rf.route/* granular subs (:rf.route/id, :rf.route/params, …) chain off [:rf/route].
Scroll restoration¶
Saved scroll positions live in a host-side, per-frame transient LRU cache keyed by frame-id. They are NOT runtime-db state. They are host-derived (read from window.scrollX/Y), meaningless server-side, and not needed to reconstitute a coherent frame on restore, SSR-hydration, or time-travel. So they never ride the trace / epoch / SSR egress wire, and they cannot rewind on an epoch restore. The pure helpers operate on a plain per-frame cache map {:positions {url [x y]} :order [url ...]}. The !-suffixed wrappers read and write the host cache.
scroll-positions-cap¶
- Kind: value
- Signature:
- Description: Soft upper bound on tracked URLs in the per-frame scroll-positions cache. It is large enough that real Back-button restoration hits saved positions, and small enough that the per-frame host cache stays bounded over long sessions.
frame-scroll-cache¶
- Kind: function
- Signature:
- Description: Read the per-frame cache map (
{:positions :order}) forframe-idfrom the host scroll-position cache, ornilwhen none. This is the value threaded into the pure nav-planning seam.
lookup-scroll-position¶
- Kind: function
- Signature:
- Description: Pure. Return the saved
[x y]forurlincache, ornilif none is saved.cacheis a per-frame cache map{:positions {url [x y]} :order [...]}; it may itself benil.
save-scroll-position¶
- Kind: function
- Signature:
- Description: Pure. Return
cachewith the scroll position forurlrecorded under:positions. The cache is LRU-capped atscroll-positions-cap. Re-saving an existing url promotes it to most-recent. A new save past the cap evicts the least-recently-used entry. The:ordervector is the recency anchor.
save-scroll-position!¶
- Kind: function
- Signature:
- Description: Record
xyforurlunderframe-idin the host scroll-position cache, applying the LRU cap via the puresave-scroll-position.
reset-scroll-cache!¶
- Kind: function
- Signature:
- Description: Test-time helper. Drop the whole host scroll-position cache so a saved position does not leak across tests.
Navigation counters and state classification¶
The nav-token and pending-nav allocators are host-side, per-frame, monotonic high-water marks — not runtime-db state. An epoch restore replaces the runtime-db partition wholesale, so it cannot rewind these counters and recycle a token still carried by a slow in-flight continuation. counter-snapshot reads them. routing-state-classification is the canonical durable/transient map that SSR, docs, and schemas key off.
counter-snapshot¶
- Kind: function
- Signature:
- Description: Read the per-frame counter snapshot for
frame-idfrom the host nav-counters cache, or{}when none. This is the value the allocation-cofx generators mint the next nav-token / pending-nav id from.
routing-state-classification¶
- Kind: value
- Signature:
-
Description: The canonical classification of every piece of per-frame routing state, by tier. Consumed by SSR, docs, and Spec-Schemas so the durable/transient split has one home.
-
:durable-runtime-db— serializable facts needed to reconstitute a coherent frame on restore / SSR-hydration; the route slice at:current. :local-subscribable-runtime-db— runtime-db state that stays subscribable and restores in local replay but is SSR-stripped fail-closed; the:pending-navigationslot.:host-transient— host-derived caches never in runtime-db; saved scroll positions and the two allocator high-water marks.
reset-nav-counters!¶
- Kind: function
- Signature:
- Description: Test-time helper. Drop the whole host nav-counters cache so a counter value does not leak across tests. Wired into the shared reset-runtime fixture via the
:routing/reset-nav-counters!late-bind key.
Multi-frame URL ownership¶
At most one frame owns the browser URL at a time. A frame claims ownership by registering with {:url-bound? true}. The resolver below names the current owner. The outbound :rf.nav/push-url fx and the inbound popstate listener both route through it — one owner, both directions.
url-owner-frame-id¶
- Kind: function
- Signature:
-
Description: Return the single frame that has explicitly declared browser-history ownership via
(rf/make-frame {:id … :url-bound? true}), ornilwhen none has. -
URL ownership is an explicit host/bootstrap policy, not an absence repair. The runtime never infers
:rf/defaultas the owner.:rf/defaultowns the URL only when it carries an explicit{:url-bound? true}, like any other frame. - Ownership resolves to the first-claimed still-live
:url-bound? trueframe (the incumbent), so a later duplicate cannot steal the URL. nilmeans no owner is declared. In that case outbound history fxs no-op and the inbound popstate listener skips.- Example:
reset-url-claims!¶
- Kind: function
- Signature:
- Description: Test-time helper. Drop the whole URL-ownership claim-order vector so a prior test's URL claim does not leak into the next. Wired into the shared reset-runtime fixture via the
:routing/reset-url-claims!late-bind key.
URL strategies¶
A :url-strategy is a frame-level config map declared on the URL-owning frame — (rf/make-frame {:id :app :url-bound? true :url-strategy routing/hash-url-strategy}). The strategy is consulted at exactly four egress/ingress points: the two history fxs, the route-link href render, and the URL-listener install. route-url, match-url, and the navigation cascade stay pure and path-form. A strategy map carries {:encode :decode :push! :replace! :install-listener!}. The side-effecting keys (:push! / :replace! / :install-listener!) are present on CLJS only. SSR ignores strategies: the server emits path-form hrefs and takes the request URL via :rf.route/handle-url-change.
history-url-strategy¶
- Kind: value
- Signature:
-
Description: The default URL strategy: HTML5 History, path-form. A frame that declares no
:url-strategyuses this. -
:encode/:decodeare identity over the app-relative URL (:decodereadspathname + search + hash). :push!/:replace!drivepushState/replaceState.:install-listener!wirespopstate.
hash-url-strategy¶
- Kind: value
- Signature:
-
Description: The hash URL strategy:
#-prefixed URLs (#/active) for no-server-rewrite static hosting and secretary-era v1 migrations.route-urlstill builds path-form/active. -
:encodemaps it to#/activeat theroute-linkhref and the history fxs. :decodestrips the leading#fromwindow.location.hash(an empty hash decodes to/).:install-listener!wireshashchange.- Example:
with-base-path¶
- Kind: function
- Signature:
- Description: A STRATEGY COMBINATOR, not a third shipped strategy. Use it when an app is deployed under a sub-path — say a host mounting several demos side by side, so an app that would otherwise own
/instead lives at/realworld/. It wrapsstrategy(either shipped strategy, or a custom one) so that:encode/:decode/:push!/:replace!/:install-listener!all account forbase. The base is stripped off every inbound URL and re-added to every outbound one, underneath whichever address-bar formstrategyalready provides.route-url/match-urland the rest of the cascade stay path-form and base-agnostic. A blank or nilbasereturnsstrategyunchanged. - Example:
Browser URL listener¶
There is no imperative boot seam to call. The browser popstate / hashchange listener is wired automatically by the :url-bound? frame LIFECYCLE (rf2-g8pbwg). When a :url-bound? true frame is created (or re-registered) and resolves as the URL owner, that step installs the listener AND syncs the current URL into the owner's route slice. Destroying the frame removes the listener. The retired install-url-listener! / remove-url-listener! / install-history-listener! / remove-history-listener! exports are GONE (pre-alpha, no back-compat shim). There is nothing to call.
- Each browser-driven change is decoded to a path-form URL by the strategy's
:decode, then dispatched synchronously as:rf.route/handle-url-changeto(url-owner-frame-id), resolved at fire time. When no frame declares:url-bound? true, the dispatch is skipped. - The listener kind (
popstatevshashchange) is resolved from the URL-owning frame's:url-strategyat install time. The owner (the dispatch target) is re-resolved at every fire. - Installation is idempotent. A re-registration that resolves as the owner tears down the prior listener before reinstalling. A losing duplicate
:url-bound? trueregistration never installs. - CLJS-only. On the JVM there is nothing to install; SSR feeds the request URL via
:rf.route/handle-url-change.
Route links¶
The :route/link registered view renders an <a href=...> from a route id. It intercepts plain left-clicks and turns them into :rf.route/url-requested dispatches. The authoring surface is also published as rf/route-link on the re-frame.core facade.
route-link¶
- Kind: component (CLJS-only; the registered
:route/linkview) - Signature:
-
Description: The registered
:route/linkview. -
:tois the only required key.:params,:query, and:fragmentare forwarded toroute-urlfor href synthesis. Every other props key passes through to the<a>element. - A plain primary-button click (no modifier keys,
defaultPreventedfalse) is intercepted. The view callspreventDefault, then dispatches[:rf.route/url-requested {:url ... :to ...}]targeted at the frame that rendered the link. - Modifier-key / middle-button clicks, and anchors carrying native-handling attributes (
:targetother than_self, or:download), defer to the browser. - A caller-supplied
:on-clickruns first. If it callspreventDefault, the framework's interception is skipped. - The rendered href is encoded through the rendering frame's
:url-strategy. - On the JVM the
:route/linkregistration renders viaroute-link-render-ssr. - Example:
route-link-render¶
- Kind: function (CLJS-only)
- Signature:
- Description: The CLJS render fn behind
route-link, exposed without the registry wrap so tests can call it directly. Same props contract and click rules asroute-link. It must run inside a frame scope, and raises:rf.error/no-frame-contextwhen rendered outside one. The render-time frame is captured so the click dispatch still targets it after the render scope has unwound.
Server-side rendering¶
route-link-render-ssr¶
- Kind: function
- Signature:
- Description: The JVM render fn for the
:route/linkview. It renders the<a href=...>shell without the click-interception logic. SSR has no DOM events to intercept, so the anchor is emitted as-is; clicks on the hydrated page run the CLJS render fn's on-click path. The href is emitted path-form regardless of:url-strategy(SSR ignores strategies), and the hydrated CLJS render re-encodes it. The authoring surface isroute-link, also published on there-frame.corefacade.
Keyword surfaces¶
The routing artefact registers a family of events, subscriptions, effects, and coeffects addressed by keyword. Loading re-frame.routing wires them all. It also registers internal machinery that apps and tools never dispatch or declare: the :rf.route.internal/* runtime events, the recordable allocation cofx (:rf.route/nav-allocation, :rf.route/pending-nav-allocation), and the :rf.route/commit-nav-counter fx. Those internals are omitted from the tables below.
Events¶
Standard events the runtime dispatches (or you dispatch) around routing.
| Event | Notes |
|---|---|
:rf.route/navigate |
Navigate to a registered route. Arities: [:rf.route/navigate target] / [:rf.route/navigate target params] / [:rf.route/navigate target params opts]. target is a route id, the reserved :rf.route/self (stay on the current route, reshape only the query), or a {:url "..."} map. params (2nd slot) are path params. opts (3rd slot) recognises :query, :query-merge, :replace?, :scroll, :fragment, :bypass-guards?. |
:rf.route/handle-url-change |
URL-change handler for popstate / initial load / SSR (default scroll :restore). A co-equal sibling of :rf.route/transitioned: same slice-rewrite logic, not a delegate. Override it for custom URL-change handling. |
:rf.route/transitioned |
URL-change handler for forward navigation — a link click or programmatic push (default scroll :top). The runtime dispatches this; you read it. |
:rf.route/url-requested |
The user clicked a framework-owned link. route-link synthesises this event; you usually let the default handler take it. |
:rf.route/navigation-blocked |
A :can-leave (leave) guard rejected a navigation. The pending nav slot carries the rejected navigation (:direction :leave). |
:rf.route/entry-blocked |
A :can-enter (enter) guard rejected a navigation — the mirror of :rf.route/navigation-blocked. The pending nav slot carries the rejected entry (:direction :enter). The natural place to redirect (e.g. to login). |
:rf.route/continue |
User-dispatched event proceeding a blocked navigation — "yes, leave the page." Re-runs :can-enter on resume. |
:rf.route/cancel |
User-dispatched event abandoning a blocked navigation — "stay here, drop the pending nav." |
Subscriptions¶
The full :rf/route slice is {:route-id :params :query :fragment :transition :error :nav-token}. The standard subs are projections of that slice plus a couple of conveniences.
| Sub | Returns |
|---|---|
:rf/route |
The full :rf/route slice {:route-id :params :query :fragment :transition :error :nav-token}. Read with @(rf/subscribe [:rf/route]). |
:rf.route/id |
Current route id (the slice's :route-id) |
:rf.route/params |
Current path params |
:rf.route/query |
Current query params |
:rf.route/transition |
:idle / :loading / :error |
:rf.route/error |
Current error map (when :transition = :error) |
:rf.route/fragment |
Current URL fragment (string or nil) |
:rf.route/chain |
Vector of route ids from parent-most to current (per :parent links) |
:rf/pending-navigation |
The pending-nav slot (per :rf/pending-navigation schema) when a navigation is blocked; nil otherwise. Read with @(rf/subscribe [:rf/pending-navigation]). |
Effects (fx)¶
| Fx | Args | Platforms | Notes |
|---|---|---|---|
[:rf.nav/push-url url-string] |
URL string | :client |
Push a new URL onto the browser history. |
[:rf.nav/replace-url url-string] |
URL string | :client |
Replace the current URL without adding a history entry. |
[:rf.nav/scroll scroll-spec] |
scroll-spec map | :client |
Restore or set scroll position. |
[:rf.nav/capture-scroll {:url url-string}] |
{:url ...} map |
:client |
Capture the current scroll position into the host-side per-frame scroll-position cache (keyed by url) before leaving a route. |
[:rf.route/with-nav-token {:rf/reply-to <reply-target> :nav-token <token>}] |
see notes | universal | Name an async-completion continuation by its canonical :rf/reply-to reply target and guard it with a navigation token. On a token match, the target is completed with the :status :ok reply map. If the token has been superseded by a later navigation, the completion is suppressed and :rf.route.nav-token/stale-suppressed fires. Optional args keys: :route-id (the captured route id, for the work-id), :value (rides the :status :ok reply map), :completed-at. |
The nav-token wrapper guards against "user navigates away mid-load". The older load's reply carries the stale token. The runtime suppresses it, so the older page's data does not overwrite the newer page's state. Full semantics in Routing → Loaders.
Coeffects (cofx)¶
Declare these on a handler via :rf.cofx/requires. Each value is delivered flat under the cofx key in the coeffects map. Both are universal (client and server).
| Cofx | Delivers |
|---|---|
:rf.route/nav-token |
The current navigation epoch token, read from [:rf.runtime/routing :current :nav-token]. Declare {:rf.cofx/requires [:rf.route/nav-token]} on an :on-match-reached handler to capture the epoch live at scheduling time and thread it into an async continuation. :rf.route/with-nav-token validates it on receipt. |
:rf.route/route-id |
The current route id, read from [:rf.runtime/routing :current :route-id]. The capture-side companion of :rf.route/nav-token. Declare both ({:rf.cofx/requires [:rf.route/nav-token :rf.route/route-id]}) so the route-loader work-id [:rf.work/route route-id nav-token loader-id] carries its complete attempt identity. |
See also¶
- re-frame.core.md — the
re-frame.corefacade: thereg-routemacro's brief row and theroute-linkview. The browser URL-change listener is NOT on the facade — it is wired automatically by the:url-bound?frame lifecycle (see Browser URL listener above). - re-frame.ssr.md — routes participate in SSR; the active route's
:headregistration is whatrender-headlooks up. - Routing guide — the narrative side: a tutorial, concepts (nav-token semantics,
:can-leaveflows, query strings, multi-frame routing), and how-to recipes. - Routing glossary — the surface vocabulary (navigate, route, loader, route guard, not-found, url-bound?).
- Coming from React Router — the mapping, and where re-frame2 routing diverges.