A lightweight, SEO-optimized React router for modern websites and applications
Routerino is a zero-dependency router tailored for React client-side rendered (CSR) websites - perfect for modern web architectures like JAMStack or simple Vite.js-React sites. It supports Prerender tags for SEO-friendly redirects and HTTP status codes, and can automatically generate a sitemap.xml file from your routes. Routerino simplifies client-side routing in React apps while providing handy SEO optimizations out of the box - a minimalist router with SEO benefits.
As a developer, I've always been passionate about creating user-friendly applications and websites. However, I've faced challenges in routing and SEO optimization for React client-side rendered (CSR) websites. For years, the de facto routing monoculture has stifled diversity and innovation in the React ecosystem. Moreover, keeping up with the frequent API churn has been time-consuming and frustrating. Driven by these challenges, I set out to create Routerino — a lightweight, zero-dependency router that simplifies routing and offers excellent SEO benefits.
I also wanted the ability to steer clear of the JSX-soup that has become prevalent in the React ecosystem. HTML is a powerful tool and it's often enough. Attempts to abstract away the web browser have led to excessive complexity, an endless black hole of bugs, and poor developer experience and delivery speed. If you've encountered such issues, you know exactly what I mean. By using plain HTML in JSX, we can build applications with simplicity. We shouldn't use this as an excuse to introduce needless complexity.
Here's a quick example of what using Routerino looks like in React:
<Routerino
title="Example.com"
routes={[
{
path: "/",
element: <p>This is the home page!</p>,
title: "My Home Page!",
description: "Welcome to my home page!",
},
{
path: "/my-first-post/",
element: (
<article>
<h1>My First Post</h1>
<p>Lorem ipsum...</p>
</article>
),
title: "My First Post",
description: "The first post on my new home page!",
tags: [{ property: "og:type", content="article" }]
},
]}
/>
For more details on getting started, see the Installation and Usage sections below.
Routerino empowers developers to define and manage routing and SEO concerns in one centralized location. This approach eliminates duplication when creating sitemaps and setting page metadata, such as descriptions or open-graph tags. The core of Routerino fits in a single file, making it easy to vendor if that suits your needs.
Key capabilities:
-
Routing
- Easy integration of simple routing for your React app (supports React v18, older versions have not yet been tested)
- Zero dependencies for lighter, more maintainable projects
- No special link components required, works great for Markdown-based pages and semantic HTML
-
SEO Optimization
- Configure title, description, and image for each route
- Set
<head>
tags for any route (either directly in your routes config, or dynamically after rendering) - Set a site-wide name to be included with page titles
- Automatically generate and maintain an up-to-date
sitemap.xml
from your routes - Implement SEO best practices out-of-the-box
- Optimize for Googlebot with pre-rendering support
-
Enhanced User Experience
- Support for sharing and social preview metadata
- Snappy page transitions with automatic scroll reset, eliminating the jarring experience of landing mid-page when navigating
Routerino is designed to work with modern browsers and has been tested with the latest versions of Chrome, Firefox, Safari, and Edge.
Ensure that you have React and React DOM installed in your project as peer dependencies. To add as a dev dependency:
npm i routerino -D
Here's a quick example of using Routerino in your React application:
<Routerino
title="Example.com"
routes={[
{
path: "/",
element: <p>This is the home page!</p>,
title: "My Home Page!",
description: "Welcome to my home page!",
},
]}
/>
Links are just regular HTML anchor tags. No need to use special <Link>
components and you can handle styling however you wish. For example: <a href="/some-page/>a link</a>
See props for full explanations and example code for more complete code samples.
Please see the default props and usage sections for more details.
All of these are optional, so it's easy to get started with nothing but a bare-bones <Routerino />
element, to get started with a working sample page. The main props you'll need are routes
and title
. See Route props for the route format.
Prop | Type | Description | Default |
---|---|---|---|
title | string | The site title | "" |
routes | RouteConfig[] | Array of route configurations | [Default Route Object] |
separator | string | Title separator | " | " |
notFoundTemplate | React.ReactNode | 404 page template | <DefaultNotFoundTemplate /> |
notFoundTitle | string | 404 page title | "Page not found [404]" |
errorTemplate | React.ReactNode | Error page template | <DefaultErrorTemplate /> |
errorTitle | string | Error page title | "Page error [500]" |
useTrailingSlash | boolean | Use trailing slashes in URLs | true |
usePrerenderTags | boolean | Use pre-render meta tags | true |
imageUrl | string | Default image URL for sharing | null |
touchIconUrl | string | Image URL for PWA homescreen icon | null |
debug | boolean | Enable debug mode | false |
titlePrefix | string | Deprecated: Title prefix | "" |
titlePostfix | string | Deprecated: Title postfix | "" |
The site title, such as "Foo.com". This will be appended to your page's title with a default separator. For example: "Page Title | Foo.com"
See RouteConfig props for more details. At a minimum a path and React element are required for each route.
- path: string;
- element: React.ReactNode;
- title?: string;
- description?: string;
- tags?: HeadTag[];
- imageUrl?: string;
A string to separate the page title from the site title. The default is |
(a pipe character). Set this to customize the separator.
Any React element for the default (or no) route match.
Default:
<>
<p>No page found for this URL. [404]</p>
<p>
<a href="/">Home</a>
</p>
</>
A title string for no route match.
Default: "Page not found [404]"
Any React element for uncaught exceptions.
Default:
<>
<p>Page failed to load. [500]</p>
<p>
<a href="/">Home</a>
</p>
</>
A title string for uncaught exceptions.
Default: "Page error [500]"
Use trailing slashes as the canonical URL. See best practices section for an explanation.
Default: true
Include meta tags to enable proper error codes like 404 when serving pages to a search crawler.
Default: true
Deprecated: use title
instead. A string to preprend to every title. Should include the brand name, a separator, and spacing, such as Example.com |
<- Note the extra end space.
Default: ""
(empty string)
Deprecated: use title
instead. A string to append to every title. Should include the brand name, a separator, and spacing, such as the following example. Note the extra starting space -> - Example.com
.
Default: ""
(empty string)
A string containing the path of the default (site-wide) image to use for sharing previews.
Default: null
A string containing the path of the image to use for PWA homescreen icon.
Default: null
Enable debug mode for additional logging and information.
Default: false
There is a default RouteConfig that will be loaded if you don't specify any routes. The default route is a basic template that can confirm your app is working and routing is good to go.
The path of the desired route, for example: "/foo/"
.
The React element to be rendered at the desired route, for example: <FooPage />
The page's title, which should not include the site's title. For example: "Contact Us"
The page's description, which will show up on search results pages.
Any desired head tags for that route. See HeadTag props for details.
Deprecated: a title prefix for this route to override the default. Use title and separator instead.
Deprecated: a title postfix for this route to override the default. Use title and separator instead.
An image URL to set for the page's og:image tag.
An array of HeadTag objects that can be added to the route to manage meta tags, links, and other elements in the <head>
section of the HTML document. These HeadTag objects are processed by the updateHeadTag
function to update or create a <head>
child tag (usually <meta>
tags). The available props and most common tag attributes are listed below, but any arbitrary tag attributes are supported. See the updateHeadTag section for more details.
-
tag
(string, default: "meta"): The HTML element to update or create. By default, it is set to "meta", but you can specify other tags like "link" or "title". -
soft
(boolean, default: false): When set totrue
, it prevents overwriting the value of an existing tag if it already exists. This is useful when you want to preserve existing tag attributes. -
name
(string): The "name" attribute of the tag. Commonly used for meta tags to specify the name of the metadata. -
property
(string): The "property" attribute of the tag. Used for Open Graph (OG) meta tags to define specific OG properties. -
content
(string): The "content" attribute of the tag. Specifies the value or content of the metadata. Sometimes two distinct meta tags may share identical content, so it's not used for matching. -
charset
(string): The "charset" attribute of the tag. Defines the character encoding for the document. -
httpEquiv
(string): The "http-equiv" attribute of the tag. Used for defining HTTP headers for the document. -
itemProp
(string): The "itemProp" attribute of the tag. Used for adding schema.org microdata to the tag. -
rel
(string): The "rel" attribute of the tag. Specifies the relationship between the current document and the linked resource. -
href
(string): The "href" attribute of the tag. Specifies the URL of the linked resource. -
src
(string): The "src" attribute of the tag. Specifies the URL of an external resource, such as an image or script. -
sizes
(string): The "sizes" attribute of the tag. Defines the sizes of the linked resource, commonly used for favicon links. -
type
(string): The "type" attribute of the tag. Specifies the MIME type of the linked resource. -
media
(string): The "media" attribute of the tag. Defines the media or device the linked resource is optimized for. -
hrefLang
(string): The "hrefLang" attribute of the tag. Specifies the language of the linked resource. -
target
(string): The "target" attribute of the tag. Defines where to open the linked resource.
Child components can access the current route and its parameters via the Routerino
or routerino
props. This prop is an object with the following properties:
- routePattern: The current route path pattern, such as
/foo/:id/
. - currentRoute: The current route path, such as
/foo/bar/
. - params: a dictionary of route parameters, such as
{id: "bar"}
. These will match the route pattern provided by thepath
prop. - updateHeadTag: a function that takes a HeadTag object and updates the head tags for the current route. This is useful for setting custom
<head>
child tags for each route, such as Open Graph tags for social previews. You may need to set this after doing some data fetches, for example. See the next section for more details.
The updateHeadTag
function is responsible for creating or updating the specified head tag. It searches for an existing tag based on the provided attributes (excluding the "content" attribute) to prevent duplicate tags. If a matching tag is found (and the soft
prop is not set to true
), the function updates the tag's attributes. If no matching tag is found, a new tag is created with the specified attributes.
Please note that the updateHeadTag
function requires at least one attribute to be provided. If no attributes are specified, an error message will be logged.
See HeadTag props for arguments and some common tag attributes.
Setting a page description:
updateHeadTag({ name: "description", content: "Some description..." });
Adding an apple touch icon (for when saving to the home screen):
updateHeadTag({
tag: "link",
rel: "apple-touch-icon",
href: "/example-icon.png",
});
While these two examples are automatically handled for you via the description
and touchIconUrl
properties in RouteConfig props, you might want to update them later or in specific scenarios.
To optimize your site for SEO and social previews when using Routerino, consider the following best practices:
- Keep page titles unique for each route. Avoid including the site title (e.g., "Foo.com") in individual page titles.
- Aim for concise, descriptive titles that accurately represent the page content.
- Ideal title length is typically 50-60 characters.
- Maintain trailing slash consistency: Search engines treat
example.com/foo
andexample.com/foo/
as different pages. - Routerino will render the same content for both versions to avoid user errors.
- Routerino will use the
useTrailingSlash
prop to automatically set the preferred URL version for search engines.
- Automate the creation of
sitemap.xml
during your build process with Routerino. - Use the
routerino-build-sitemap
command to generate the sitemap from your routes (see Generating a Sitemap from Routes).
- Add an
imageUrl
to each route for page-specific social preview images. - Set a default
imageUrl
via the Routerino prop for pages without unique images. - Ensure preview images meet platform-specific size requirements (e.g., 1200x630 pixels for Facebook).
- Include any other Open Graph tags you need for each page with the
updateHeadTag
function.
- Provide unique, informative descriptions for each route.
- Keep descriptions between 100-200 characters. This range is optimal for most search engines.
- Descriptions longer than ~150 characters may be truncated in search results.
- Use semantic HTML elements in your components for better content structure.
- Implement structured data (JSON-LD) where applicable to enhance rich snippets in search results.
- Ensure your site is mobile-friendly and loads quickly for better search engine rankings.
By following these practices, you'll improve your site's SEO performance and social media presence when using Routerino.
You can use the included CLI tool routerino-build-sitemap
to create a sitemap.xml for your site. Adjust the arguments to your needs. Make sure to run a build first (or otherwise ensure the directory for the sitemap exists). Routes with route params are not added to the sitemap. This sitemap only includes the location entry, as the others are mostly ignored by Google. Node 16+ should be installed and available in the path. Since it would be an SEO problem to not have the robots.txt
file pointing to the sitemap, we include it if missing. If you create your own, make sure to include the sitemap URL in it.
- routeFilePath: The path to whichever file contains your routes, in order for the sitemap build tool to find them. The routes can be defined either inline in the Routerino props, or kept in an array named
routes
,Routes
, or just exported as default. This might be something likesrc/Router/index.jsx
, orsrc/App.jsx
. Whichever file you've put your routes in should be used. - hostname: The domain to use as the base for the URLs in the sitemap. E.g.
https://example.com
. Make sure to include or exclude thewww
prefix as desired. - outputDir: The path to write the new sitemap XML file. This would usually be a build directory, e.g.
dist
orbuild
, or maybe something likepublic
if you wanted to check in the sitemap to your repo (set it as a pre-commit step in that case).
routerino-build-sitemap routeFilePath=src/routes.jsx hostname=https://example.com outputDir=dist
✅ sitemap.xml with 42 URLs written to dist
✅ robots.txt written to dist
Add routerino-build-sitemap
to your build command to update automatically on every build.
Example package.json build script: "build": "vite build && routerino-build-sitemap routeFilePath=src/routes.jsx hostname=https://example.com outputDir=dist",
If you're starting from scratch and wondering "How do I create a React project with Routerino?", here's a recommended approach:
-
First, ensure you have Node.js and npm (Node Package Manager) installed on your system. If you're just getting started, consider using a Node version manager like Volta, fnm, or asdf for easy installation and management of Node.js versions.
-
We recommend using Vite for a fast and lean development experience. Vite is a modern build tool that focuses on speed and simplicity. To create a new React project with Vite, run the following command in your terminal:
npm create vite@latest my-react-app -- --template react
This command will create a new directory called my-react-app
with a basic React project structure.
- Navigate to your new project directory:
cd my-react-app
- Install the project dependencies using npm:
npm install
This command will read the package.json
file in your project and install all the necessary dependencies.
- Now, add Routerino to your project as a development dependency:
npm install routerino --save-dev
This command will install the latest version of Routerino and save it to your package.json
file under the devDependencies
section.
With these steps, you'll have a new React project set up with Vite as the build tool and Routerino installed as a development dependency. You can now start building your application with React & Routerino.
Somewhere in your project, such as in your src/App.jsx
file, import Routerino and add it to your code. Define your routes and configure the site title.
import React from "react";
import Routerino from "routerino";
// example pages
import HomePage from "./HomePage";
import AboutPage from "./AboutPage";
import ContactPage from "./ContactPage";
const routes = [
{
path: "/",
element: <HomePage />,
title: "Home",
description: "Welcome to my website!",
},
{
path: "/about/",
element: <AboutPage />,
title: "About",
description: "Learn more about us.",
},
{
path: "/contact/",
element: <ContactPage />,
title: "Contact",
description: "Get in touch with us.",
},
];
const App = () => (
<main>
<nav>
<a href="/">Home</a>
</nav>
<Routerino
title="Foo.com"
routes={routes}
notFoundTitle="Sorry, but this page does not exist."
errorTitle="Yikes! Something went wrong."
/>
<footer>
<p>
Learn more <a href="/about/">about us</a> or{" "}
<a href="/contact/">contact us</a> today.
</p>
</footer>
</main>
);
export default App;
This example includes the full React configuration. It might take the place of src/main.jsx
or an index.js
file. Also suitable for use in a code-pen.
import React from "react";
import { render } from "react-dom";
import Routerino from "routerino";
const title = "Example.com";
const routes = [
{
path: "/",
element: <p>Welcome to Home</p>,
title: "Home",
description: "Welcome to my website!",
},
{
path: "/about/",
element: <p>About us...</p>,
title: "About",
description: "Learn more about us.",
},
{
path: "/contact/",
element: (
<div>
<h1>Contact Us</h1>
<p>
Please <a href="mailto:[email protected]">send us an email</a> at
[email protected]
</p>
</div>
),
title: "Contact",
description: "Get in touch with us.",
},
];
const App = () => (
<main>
<nav>
<a href="/">Home</a>
</nav>
<Routerino
{...{
title,
routes,
}}
/>
<footer>
<p>
Learn more <a href="/about/">about us</a> or{" "}
<a href="/contact/">contact us</a> today.
</p>
</footer>
</main>
);
render(<App />, document.getElementById("root"));
If you prefer to include Routerino directly in your project instead of using it as a dependency, you can easily vendor the library. Vendoring allows you to have full control over the version of Routerino used in your project and eliminates the need to manage it as an external dependency.
To vendor Routerino, follow these steps:
-
Download the
routerino.jsx
file from the Routerino repository. -
Place the
routerino.jsx
file in a suitable location within your project's source directory. For example, you could create avendor
folder and place the file there:
your-project/
├── src/
│ ├── vendor/
│ │ └── routerino.jsx
│ └── ...
└── ...
- Update your import statements to reference the vendored
routerino.jsx
file instead of the package:
// Before (importing from the package)
import { Router, Route } from "routerino";
// After (importing from the vendored file)
import { Router, Route } from "./vendor/routerino";
-
You're all set! Routerino is now vendored in your project, and you can use it as before.
-
If you want to use the sitemap generation script, copy
build-sitemap.js
into your project and reference it directly with the same arguments as above. For example:./build-sitemap.js routeFilePath=src/App.jsx hostname=https://example.com outputDir=build
By vendoring Routerino, you have full control over the code and can make any necessary modifications directly to the routerino.jsx
file. However, keep in mind that you'll need to manually update the vendored file if you want to incorporate any future updates or bug fixes from the main Routerino repository.
There is a lot of information on SEO and social previews. Here are some sources for further reading on best-practices.
Contributions are always welcome. Please feel free to create an issue or submit a pull request. Just remember to keep it simple!
Routerino is MIT licensed.