This is outdated documentation for Sycamore.
For up-to-date documentation, see the latest version (v0.8).
Routing
Routers are the backbone of SPAs (Single Page Apps). They handle displaying different pages
depending on the URL. When an anchor tag (<a>
) is clicked, the router will intercept it and
navigate to the correct page without performing a full refresh. This makes navigation feel faster
and smoother.
Adding sycamore-router
To add routing to your Sycamore app, install the
sycamore-router
crate from crates.io.
= "0.6.3"
Compatibility with sycamore
Note that the major version number for sycamore-router
corresponds to the same major version
number for sycamore
(e.g. sycamore-router v0.5.x
is compatible with sycamore v0.5.x
).
Creating routes
Start off by adding use sycamore_router::{Route, Router, RouterProps}
to the top of your source
code. This imports the symbols needed to define our router.
The heart of the router is an enum
. Each variant of the enum
represents a different route. To
make our enum
usable with Router
, we will use the Route
derive macro to implement the required
traits for us.
Here is an example:
Note that each variant is marked with either the #[to(_)]
or #[not_found]
attribute.
The #[to(_)]
attribute designates a route. For example, #[to("/about")]
designates the route for
the about page.
The #[not_found]
is a fallback route. It is the route that matches when all the other routes
don’t. There must be one, and only one route marked with #[not_found]
. Forgetting the not found
route will cause a compile error.
Routes syntax
Static routes
The simplest routes are static routes. We already have the "/"
and "/about"
routes in our above
example which are both static.
Static routes can also be nested, e.g. "/my/nested/path"
.
Dynamic parameters
Path parameters can be dynamic by using angle brackets around a variable name in the route’s path. This will allow any segment to match the route in that position.
For example, to match any route with "hello"
followed by a name, we could use:
Hello
The <name>
parameter is captured by the name
field in the Hello
variant. For example, if we
were to visit /hello/sycamore
, we would find
Hello
Multiple dynamic parameters are allowed. For example, the following route…
Repo
…would match /repo/sycamore-rs/sycamore
with a value of
Repo
Dynamic segments
Dynamic segments can also be captured using the <param..>
syntax.
For example, the following route will match "page"
followed by an arbitrary number of segments
(including 0 segments).
Page
Dynamic segments match lazily, meaning that once the next segment can be matched, the capture will
be completed. For example, the following route will not capture the final end
segment.
Path
Unit variants
Enum unit variants are also supported. The following route has the same behavior as the hello example from before.
Hello
Capture types
Capture variables are not limited to String
. In fact, any type that implements the
FromParam
trait can
be used as a capture.
This trait is automatically implemented for types that already implement FromStr
, which includes
many standard library types.
Because FromParam
is fallible, the route will only match if the parameter can be parsed into the
corresponding type.
For example, /account/123
will match the following route but /account/abc
will not.
Account
Likewise, the
FromSegments
trait is the equivalent for dynamic segments.
Using Router
To display content based on the route that matches, we can use a Router
.
template!
Router
is just a component like any other. The props accept a closure taking a StateHandle
of
the matched route as a parameter and an “integration”. The integration is for adapting the router to
different environments (e.g. server-side rendering). The HistoryIntegration
is a built-in
integration that uses the
HTML5 History API.
Any clicks on anchor tags (<a>
) created inside the Router
will be intercepted and handled by the
router.
Server-side rendering and StaticRouter
Whereas Router
is used inside the context of a browser, StaticRouter
can be used for SSR.
The difference between a Router
and a StaticRouter
is that the route is provided to
StaticRouter
during the initialization phase. The initial route is provided as an argument to
StaticRouterProps::new
.
This is so that StaticRouter
can return a Template
immediately without blocking to wait for the
route preload. The route is expected to be resolved separately using the Route::match_path
function.
let route = match_path;
template!
Integrations
TODO: docs for creating custom router integrations.
Using navigate
Calling navigate
navigates to the specified url
. The url should have the same origin as the app.
This is useful for imperatively navigating to an url when using an anchor tag (<a>
) is not
possible/suitable (e.g. when submitting a form).
Data fetching and preloading
When data fetching (e.g. from a REST API) is required to load a page, it is recommended to preload the data. This will cause the router to wait until the data is loaded before rendering the page, removing the need for some “Loading…” indicator.
use spawn_local;
template!
rel="external"
By default, the router will intercept all <a>
elements that have the same origin as the current
page. Sometimes, we just want the browser to handle navigation without being intercepted by the
router. To bypass the router, we can add the rel="external"
attribute to the anchor tag.
template!