<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>minimal-routing</title>
+ <style>
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
+ background: hsl(275deg 10% 90%);
+ color: hsl(275deg 90% 10%);
+ inline-size: min(100% - 16px, 1080px);
+ margin-inline: auto;
+ }
+
+ header,
+ main {
+ display: flex;
+ justify-content: center;
+ }
+
+ header {
+ border-block-end: 2px solid hsl(275deg 90% 10%);
+ margin-block-end: 8px;
+ }
+
+ nav {
+ flex-basis: 20%;
+ display: flex;
+ flex-direction: column;
+ }
+
+ section {
+ flex-basis: 80%;
+ display: flex;
+ flex-direction: column;
+ }
+
+ nav>a {
+ padding-block: 16px;
+ margin-inline-end: 8px;
+ }
+
+ a {
+ color: hsl(275deg 50% 50%);
+ text-decoration: none;
+ font-weight: 700;
+ border-radius: 4px;
+ transition: background-color 300ms;
+ }
+
+ a:hover,
+ a:focus {
+ background: hsl(275deg 20% 85%);
+ transition: background-color 150ms;
+ }
+
+ code {
+ background: hsl(275deg 25% 85%);
+ border-radius: 3px;
+ font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
+ padding: 0 3px;
+ }
+
+ p.subtitle {
+ font-weight: 700;
+ }
+ </style>
</head>
<body>
<header>
- <a data-router data-route="home" href="/home">Go to the home page</a>
- <a data-router data-route="page_1" href="/page_1">Go to page 1</a>
- <a data-router data-route="page_2" href="/page_2">Go to page 2</a>
- <a data-router data-route="page_3" href="/page_3">Go to page 3</a>
+ <h1>minimal-routing</h1>
</header>
<main>
- <article data-page data-route="home">
- Hello from the home page!
- </article>
- <article data-page data-route="page_1">
- Hello from page 1!
- </article>
- <article data-page data-route="page_2">
- Hello from page 2!
- </article>
- <article data-page data-route="page_3">
- Hello from page 3!
- </article>
+ <nav>
+ <a data-router data-route="home" href="/home">Home</a>
+ <a data-router data-route="page_1" href="/page_1">Page 1</a>
+ <a data-router data-route="page_2" href="/page_1">Page 2</a>
+ <a data-router data-route="page_3" href="/page_1">Page 3</a>
+ </nav>
+
+ <section>
+ <article data-page data-route="home">
+ <p class="subtitle">Hello from the home page! 🏠</p>
+ <p>This is the page at the root of the website.</p>
+ <p><a data-router data-route="page_1" href="/page_1">Click here</a> to go to <code>/page_1</code>, which is a completely different page from this one.</p>
+ </article>
+ <article data-page data-route="page_1">
+ <p class="subtitle">As promised, this is a completely different page.</p>
+ <p>Look at the URL path - it changed.</p>
+ <p>But this page loaded instantly. If you observe the network tab in DevTools, no network requests have been made.</p>
+ <p>And if you observe the DOM, only this <code><article></code> tag has changed.</p>
+ <p>How does this work? <a data-router data-route="page_2" href="/page_2">Click here</a> to go to <code>/page_2</code> and find out.</p>
+ </article>
+ <article data-page data-route="page_2">
+ <p class="subtitle">All the routing logic has been implemented client-side in JavaScript.</p>
+ <p>We've actually never left the root <code>index.html</code> page - check the source.</p>
+ <p>This behavior is the signature characteristic of an <dfn><abbr title="Single Page Application">SPA</abbr></dfn>.</p>
+ <p><a data-router data-route="page_3" href="/page_3">Click here</a> to go to <code>/page_3</code> and learn more.</p>
+ </article>
+ <article data-page data-route="page_3">
+ <p class="subtitle">There are a few important behaviors that are often overlooked when implementing client-side routing:</p>
+ <ul>
+ <li>The backward and forward buttons need to work as expected.</li>
+ <li>Direct links to specific pages need to work.</li>
+ <li>Invalid routes need to return <code>HTTP 404</code> errors (this behavior is critical for <dfn><abbr title="Search Engine Optimization">SEO</abbr></dfn>).</li>
+ </ul>
+ <p>The purpose of this website is to isolate the problem of client-side routing and provide a minimal reference implementation for it.</p>
+ <p>All the behaviors above have been implemented for this website in about 50 total lines of JavaScript.</p>
+ <p><a href="https://github.com/ardislu/minimal-routing">Click here</a> to view the source code on GitHub.</p>
+ </article>
+ </section>
</main>
<script>
const routers = document.querySelectorAll('[data-router]');
- const main = document.querySelector('main');
+ const content = document.querySelector('section');
const pages = Array.from(document.querySelectorAll('[data-page]')); // Must convert to array to preserve elements
// Display the appropriate page based on the URL path (does NOT modify browser history)
let match = false;
for (const page of pages) {
if (page.dataset.route === path) {
- main.appendChild(page);
+ content.appendChild(page);
match = true;
}
else {