A tiny React router that works exactly as expected with native Javascript:

// App.js
import React from 'react';
import router from 'react-plain-router';

// Wrap it and you can use normal anchor links
export default router(({ path, query, hash }) => (
      <a href="/">Go Home</a>
      <a href="/about">About us</a>

    {path === '/' && <div>Hello world!</div>}
    {path === '/about' && <div>About me</div>}

You have to wrap your app with router() and then both &lt;a&gt; links and window.history.pushState() will work as expected. It will trigger a re-render when any of these properties change: pathquery or hash.

If you have parameters or complex routes you can combine it with my other library pagex for a cleaner syntax:

import router from 'react-plain-router';
import page from 'pagex';

export default router(() => (
    {page('/', () => <div>Hello world!</div>)}
    {page('/users', () => <ul>...</ul>)}
    {page('/users/:id', id => <User id={id} />)}

If a link has the attribute target, then this library will ignore it and let the browser handle it. This is very useful for target="_blank", so that the link is opened in a new tab as usual. But it will also work with target="_self", where the router will ignore the link and thus perform a full-refresh.

An event named navigation will be triggered on window every time there’s a re-render. You can see the parts with e.detail, which is very useful for debugging:

// When loading /greetings?hello=world#nice
window.addEventListener('navigation', e => {
  console.log('NAVIGATION', e.detail);
  // {
  //   path: '/greetings',
  //   query: { hello: 'world' },
  //   hash: 'nice'
  // }

Internally, it works by using the bubbling events at the document level and then handling any link click. window.locationbecomes the source of truth instead of keeping an context or global store, which makes it more reliable to interact with native Javascript or http events.


This HOC function accepts a callback, which will be passed an arguments with the props from above and these 3 extra props:

  • pathpathname (String): the current url path, similar to the native pathname. Example: for /greetings it will be '/greetings'. An empty URL would be '/'.
  • query (Object | false): an object with key:values for the query in the url. Example: for /greeting?hello=world it will be { hello: 'world' }.
  • hash (String | false): the hash value without the #. Example: for /hello#there it will be 'there'.

A fully qualified url will parse as this:

// /greetings?hello=world#nice
router(({ path, query, hash, ...props }) => {
  expect(query).toEqual({ hello: 'world' });

Subscribe to the Newsletter

Get our latest news,tutorials,guides,tips & deals delivered to your inbox.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.