Side Effects

Curi side effects are permanent router response handlers that are run after those registered using router.observe and router.once.

Whenever a new response is generated, all of the side effect functions will be called. They will be given an object with the new response object, a navigation object with some extra routing data (the navigation action the previous response), and the router object.

function logResponse({ response }) {
  // call your logging API to record the response

Adding Side Effects

Side effects are provided to your router with the sideEffects property of the options object. This is an array of observer functions.

let router = createRouter(browser, routes, {
  sideEffects: [logResponse, updateTitle]

Side effects are always run after observers registered using router.observe and router.once. Because those forms of response handler registration are primarily used for rendering the application, this means that the side effects will be called after the application has re-rendered.

let router = createRouter(browser, routes, {
  sideEffects: [logResponse]

let render = () => {
  // render the app


// whenever there is a response, render will be
// called before logResponse


Curi's @curi/router package provides three side effects:

  • The announce side effect announces navigation for screen readers.
  • The scroll side effect scrolls to the top of the page after navigation.
  • The title side effect sets the document's title after navigation.
import { announce, scroll, title } from "@curi/router";

let router = createRouter(browser, routes, {
  sideEffect: [
    announce(({ response }) => {
      return `Navigated to ${response.location.pathname}`;
    title(({ response }) => {
      return `${response.meta.title}`;

Creating Side Effects

When creating your own side effect, you can write a regular function or a side effect "factory".

function mySideEffect({ response, navigation }) {
  console.log('Navigating to', response.location);
  console.log('Navigation action:', navigation.action);

let router = createRouter(browser, routes, {
  sideEffects: [mySideEffect]

A side effect factory lets create a more customizable side effect.

function AnalyticsLogger(options) {
  // do some setup with the provided options
  let logger = setupMyLogger(options);

  // and return the actual side effect function
  return sideEffect({ response }) {

You may want to review the response properties to know which properties you should expect a response to have.