Skip to content

Instantly share code, notes, and snippets.

@J-Cake
Created September 4, 2025 17:20
Show Gist options
  • Save J-Cake/1e907e140b4771034be24dba5bef3ade to your computer and use it in GitHub Desktop.
Save J-Cake/1e907e140b4771034be24dba5bef3ade to your computer and use it in GitHub Desktop.
React Router

I hate dependencies. Here's a router that you can copy+paste into your code. Does it have all the features? No. Does it do X? Fuck off. It's a simple router. Take it. Enjoy it.

Usage

import Router, {RouterView, Link} from './router.js';

export default function App() {
  return <>
    <Router config={{
      '/': matches => <Home matches={matches} />
    }}>
      <section id="app">
        <RouterView />
      </section>
    </Router>
  </>;
}

export function Home(props: { matches: URLPatternMatch }) {
  return <>
    <span>{props.matches.length}</span>
    
    <Link to="/home">Home</Link>
  </>;
}
import React from 'react';
import {config} from "./main.js";
type RouterContextType = {
url: URL;
navigate: (to: string) => void;
page: React.ReactNode;
};
const RouterContext = React.createContext<RouterContextType | null>(null);
export type RouterConfig = {
[Path in string]: (props: { path: Path, match: URLPatternResult }) => React.ReactNode;
}
export default function Router(props: { config: RouterConfig, children?: React.ReactNode }) {
const [url, setUrl] = React.useState(new URL(window.location.href));
React.useEffect(() => {
let handler: (e: PopStateEvent) => void;
window.addEventListener('popstate', handler = e => {
e.preventDefault();
setUrl(new URL(window.location.href));
});
return () => window.removeEventListener('popstate', handler);
});
const navigate = React.useCallback((to: string) => {
window.history.pushState(null, "", to);
setUrl(new URL(window.location.href));
}, [setUrl]);
const page = React.useMemo(() => {
for (const [path, component] of Object.entries(props.config)) {
const match = new URLPattern(path, config.app).exec(url);
if (match)
return <div id="main">
{component({path, match})}
</div>;
}
return null;
}, [url, props.config]);
return <RouterContext.Provider value={{url, navigate, page}}>
{props.children}
</RouterContext.Provider>;
}
export function Link(props: { to: string, children: React.ReactNode, className?: string }) {
const ctx = React.useContext(RouterContext);
if (!ctx) throw new Error("Link must be used inside a Router");
const handle = function(e: React.MouseEvent<HTMLAnchorElement>) {
if (e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey) {
e.preventDefault();
ctx.navigate(props.to);
}
};
return <a href={props.to} onClick={handle} className={props.className}>
{props.children}
</a>
}
export function RouterView(): React.ReactNode {
const ctx = React.useContext(RouterContext);
if (!ctx) throw new Error("RouterView must be used inside a Router");
if (ctx.page)
return ctx.page;
else
return <div>{"Not found"}</div>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment