Git Product home page Git Product logo

router-component's Introduction

Build Status npm version

<router-component>

A simple, declarative router component for single-page apps that allows you to load Web Components dynamically when urls are requested, without performing a hard reload of the entire page.

Benefits

  • Very lightweight (there is very little code in this library)
  • Only provides routing needs and nothing more
  • Easy, declarative html syntax -- no complex configuration files or routing engines
  • Automatically intercepts all <a> tags on a page (that contain relative hrefs) to prevent them from causing page reloads, which use pushState() API.

Installation

npm i router-component

Prerequisites

This library assumes you are using a browser that supports Web Components and that you are using them as your routed elements. They are the future of the web and are already implemented natively in browsers.

For advanced usage of this library, you will need to know Regular Expressions and how they work in JavaScript.

Usage

Basic Example

<!-- index.html -->

<html>
<head>
    <script type="module" src="node_modules/router-component/dist/router-component.js"></script>
    <script type="module">
        customElements.define('first-page', class extends HTMLElement {
            connectedCallback() {
                this.innerHTML = `
                    Navigated to ${window.location.pathname} <br />` + //"/"
                    `Go to <a href="/second/view">second page</a>.`
                ;
            }
        });
        customElements.define('second-page', class extends HTMLElement {
            connectedCallback() {
                this.innerHTML = `
                    Navigated to ${window.location.pathname} <br />` + // "/second/view" OR "/second/view/"
                    `Go to <a href="/doesnt/work">a page that doesnt exist</a>.`
                ;
            }
        });
        customElements.define('page-doesnt-exist', class extends HTMLElement {
            connectedCallback() {
                this.innerHTML = `<p>Wrong page, go to <a href="/">first page again</a></p>`;
            }
        });
    </script>
</head>
<body>
<router-component>
    <first-page path="^/(index.html)?$"></first-page>
    <second-page path="/second/view[/]?"></second-page>
    <page-doesnt-exist path=".*"></page-doesnt-exist>
</router-component>
</body>
</html>

More Examples

Code samples showing how to use this package can be found in the examples folder. To run them, pull down this project and

npm run start-server

Which will make the examples available at http://localhost:3239/examples/.

<router-component> API

The <router-component> can be passed the following:

Option Type Description
hash-scroll-behavior Number The ScrollBehavior value that will be used when the router scrolls to the anchored element with an id attribute that matches the hash identifier in the URL requested.
hash-scroll-delay Number The number of milliseconds to delay the router's scrolling to the anchored element on a page
show-delay Number The number of milliseconds to delay before the router adds each page to the DOM and triggers its connectedCallback (useful to implement some sort of animation or transition of a previous page first)
hide-delay Number The number of milliseconds to delay before the router removes each page from the DOM and triggers its disconnectedCallback
showing-page Custom Event Event that is triggered when the page is added to the DOM. The page that is added is passed as the detail property on the emitted event.
hiding-page Custom Event Event that is triggered when the page is removed from the DOM. The page being removed is passed as the detail property on the emitted event.

Route API

Each child element of <router-component> should be a CustomElement so that the following attributes can be passed to them:

Option Type Description
path String A regex expression that the browser URL needs to match in order for the component to render. Capture groups are also supported to allow for dynamic parameters in URLs.
search-params String A search string regex that the requested page would need to have in order to match. Setting this value to foo=[bar|baz] would match index.html?foo=bar for instance)
document-title String The title of the document that will be shown when the route is active

Routing

The goal of this package is to leverage the use of existing browser APIs, while providing only a few key pieces of logic that make routing easier, which is identified below.

Changing Routes

There are two ways that a route can be changed.

  1. By clicking on a relative link that is nested within a route element or
  2. Programmatically using the pushState() or replaceState() API
window.history.pushState({}, null, '/new-url');

Each method will trigger the route-changed event that is dispatched by the router component itself, which is illustrated in the next section below.

In the rare case you would like to push a new state or change the current location without triggering a new route, you can pass triggerRouteChange flag like this:

window.history.pushState({ triggerRouteChange: false }, null, '/new-url');

Router will clean up the triggerRouteChange property in history.state, so you don't need to worry about clearing it out.

Detecting Route Changes

You can listen to route changes that are triggered either by link clicks or via History's pushState() or replaceState API

<html>
    <head>
        <script
            type="module"
            src="node_modules/router-component/dist/router-component.js"
        ></script>
        <script type="module">
            const router = document.body.querySelector('router-component');
            router.addEventListener('route-changed', () => {
                // called everytime the route changes!
            });
        </script>
    </head>
    <body>
        <router-component>
            <other-page path="/other[/]?"></other-page>
            <fallback-page path=".*"></fallback-page>
        </router-component>
    </body>
</html>

Development

To run tests:

npm test

To debug and run locally:

npm start

router-component's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar markcellus avatar shinobi5 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

router-component's Issues

Nested routing?

Does this component allow nested routing? It looks like it assumes at most one <router-component> for the entire app.

Use case: I want to be able to have a nested component handle routing within the component itself. E.g. When I use a tabs component, clicking on separate tabs updates the URL and triggers different views.

Invalid hashes error

when navigating to hashes like /#!, the scrollToHash method throws the following error:

DOMException: Failed to execute 'querySelector' on 'Element': '[id=!]' is not a valid selector.

Dependabot can't resolve your JavaScript dependency files

Dependabot can't resolve your JavaScript dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Error whilst updating @open-wc/karma-esm in /package-lock.json:
No matching version found for @open-wc/building-utils@^2.17.0.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Support hash links clicked on nested routes

After being routed to a component using a nested path (e.g. /path/to/my/first/route), clicking on a link with a hash

<a href="#comment2">hashed link</a>

Should scroll to the element with the id of comment2 at the same route instead of attempting to route to /#comment2.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.