{"id":15541904,"url":"https://github.com/markcellus/router-component","last_synced_at":"2026-04-10T05:04:46.675Z","repository":{"id":30345324,"uuid":"33897740","full_name":"markcellus/router-component","owner":"markcellus","description":"A simple, declarative router for Web Components","archived":false,"fork":false,"pushed_at":"2023-05-01T01:02:55.000Z","size":5201,"stargazers_count":34,"open_issues_count":7,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-04-01T08:32:47.818Z","etag":null,"topics":["custom-element-router","declarative-routing","html-router","js-router","lit-router","router","router-component","routing","spa-router","web-router","webcomponent-router"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markcellus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-04-13T22:35:53.000Z","updated_at":"2025-08-08T14:52:07.000Z","dependencies_parsed_at":"2025-04-23T17:11:24.670Z","dependency_job_id":"7921a892-8753-4c25-86de-2bdf33223942","html_url":"https://github.com/markcellus/router-component","commit_stats":null,"previous_names":["mkay581/route-manager","mkay581/router-js","mkay581/router-component"],"tags_count":85,"template":false,"template_full_name":null,"purl":"pkg:github/markcellus/router-component","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markcellus%2Frouter-component","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markcellus%2Frouter-component/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markcellus%2Frouter-component/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markcellus%2Frouter-component/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markcellus","download_url":"https://codeload.github.com/markcellus/router-component/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markcellus%2Frouter-component/sbom","scorecard":{"id":619793,"data":{"date":"2025-08-11","repo":{"name":"github.com/markcellus/router-component","commit":"2f42ad275b734ee6f546c0aa77519ef28287f4f9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.1,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":-1,"reason":"Found no human activity in the last 30 changesets","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/dependabot-automerge.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/markcellus/router-component/dependabot-automerge.yml/master?enable=pin","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: topLevel 'contents' permission set to 'write': .github/workflows/dependabot-automerge.yml:6","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"21 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-593f-38f6-jp5m","Warn: Project is vulnerable to: GHSA-x2rg-q646-7m2v","Warn: Project is vulnerable to: GHSA-jgmv-j7ww-jx2x","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5","Warn: Project is vulnerable to: GHSA-pq67-2wwv-3xjx","Warn: Project is vulnerable to: GHSA-8cj5-5rvv-wf4v","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T04:55:58.253Z","repository_id":30345324,"created_at":"2025-08-21T04:55:58.254Z","updated_at":"2025-08-21T04:55:58.254Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31584662,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["custom-element-router","declarative-routing","html-router","js-router","lit-router","router","router-component","routing","spa-router","web-router","webcomponent-router"],"created_at":"2024-10-02T12:20:00.630Z","updated_at":"2026-04-09T03:34:02.570Z","avatar_url":"https://github.com/markcellus.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/markcellus/router-component.svg?branch=master)](https://travis-ci.org/markcellus/router-component)\n[![npm version](https://badge.fury.io/js/router-component.svg)](https://www.npmjs.com/package/router-component)\n\n# `\u003crouter-component\u003e`\n\nA simple, declarative router component for single-page apps that allows you to load [Web Components](https://www.webcomponents.org/introduction)\ndynamically when urls are requested, without performing a hard reload of the entire page.\n\n## Benefits\n\n-   Very lightweight (there is very little code in this library)\n-   Only provides routing needs and nothing more\n-   Easy, declarative html syntax -- no complex configuration files or routing engines\n-   Automatically intercepts all `\u003ca\u003e` tags on a page (that contain relative `href`s) to prevent them from causing page\n    reloads, which use [pushState()](http://w3c.github.io/html/browsers.html#dom-history-pushstate) API.\n\n## Installation\n\n```\nnpm i router-component\n```\n\n## Prerequisites\n\nThis library assumes you are using a browser that supports [Web Components](https://www.webcomponents.org/introduction)\nand that you are using them as your routed elements. They are the future of the web and are already implemented\nnatively in browsers.\n\nFor advanced usage of this library, you will need to know\n[Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) and how\nthey work in JavaScript.\n\n## Usage\n\n### Basic Example\n\n\u003c!-- prettier-ignore --\u003e\n```html\n\u003c!-- index.html --\u003e\n\n\u003chtml\u003e\n\u003chead\u003e\n    \u003cscript type=\"module\" src=\"node_modules/router-component/dist/router-component.js\"\u003e\u003c/script\u003e\n    \u003cscript type=\"module\"\u003e\n        customElements.define('first-page', class extends HTMLElement {\n            connectedCallback() {\n                this.innerHTML = `\n                    Navigated to ${window.location.pathname} \u003cbr /\u003e` + //\"/\"\n                    `Go to \u003ca href=\"/second/view\"\u003esecond page\u003c/a\u003e.`\n                ;\n            }\n        });\n        customElements.define('second-page', class extends HTMLElement {\n            connectedCallback() {\n                this.innerHTML = `\n                    Navigated to ${window.location.pathname} \u003cbr /\u003e` + // \"/second/view\" OR \"/second/view/\"\n                    `Go to \u003ca href=\"/doesnt/work\"\u003ea page that doesnt exist\u003c/a\u003e.`\n                ;\n            }\n        });\n        customElements.define('page-doesnt-exist', class extends HTMLElement {\n            connectedCallback() {\n                this.innerHTML = `\u003cp\u003eWrong page, go to \u003ca href=\"/\"\u003efirst page again\u003c/a\u003e\u003c/p\u003e`;\n            }\n        });\n    \u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003crouter-component\u003e\n    \u003cfirst-page path=\"^/(index.html)?$\"\u003e\u003c/first-page\u003e\n    \u003csecond-page path=\"/second/view[/]?\"\u003e\u003c/second-page\u003e\n    \u003cpage-doesnt-exist path=\".*\"\u003e\u003c/page-doesnt-exist\u003e\n\u003c/router-component\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\n```\n\n### More Examples\n\nCode samples showing how to use this package can be found in the [examples](examples) folder. To run them, pull down this project\nand\n\n```bash\nnpm run start-server\n```\n\nWhich will make the examples available at http://localhost:3239/examples/.\n\n## `\u003crouter-component\u003e` API\n\nThe `\u003crouter-component\u003e` can be passed the following:\n\n| Option                 | Type                                                               | Description                                                                                                                                                                                                                                                                                         |\n| ---------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `hash-scroll-behavior` | Number                                                             | The [ScrollBehavior](https://drafts.csswg.org/cssom-view/#enumdef-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](https://www.w3.org/TR/html401/struct/links.html#h-12.2.3). |\n| `hash-scroll-delay`    | Number                                                             | The number of milliseconds to delay the router's scrolling to the anchored element on a page                                                                                                                                                                                                        |\n| `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)                                                                                            |\n| `hide-delay`           | Number                                                             | The number of milliseconds to delay before the router removes each page from the DOM and triggers its `disconnectedCallback`                                                                                                                                                                        |\n| `showing-page`         | [Custom Event](https://dom.spec.whatwg.org/#interface-customevent) | 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.                                                                                                                                                          |\n| `hiding-page`          | [Custom Event](https://dom.spec.whatwg.org/#interface-customevent) | 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.                                                                                                                                                      |\n\n## Route API\n\nEach child element of `\u003crouter-component\u003e` should be a\n[CustomElement](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements) so that the following attributes\ncan be passed to them:\n\n| Option           | Type   | Description                                                                                                                                                               |\n| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `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.   |\n| `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) |\n| `document-title` | String | The [title of the document](https://html.spec.whatwg.org/multipage/dom.html#document.title) that will be shown when the route is active                                   |\n\n## Routing\n\nThe 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.\n\n### Changing Routes\n\nThere are two ways that a route can be changed.\n\n1. By clicking on a relative link that is nested within a route element or\n1. Programmatically using the [`pushState()`](http://w3c.github.io/html/browsers.html#dom-history-pushstate) or [`replaceState()`](http://w3c.github.io/html/browsers.html#dom-history-replacestate) API\n\n```javascript\nwindow.history.pushState({}, null, '/new-url');\n```\n\nEach method will trigger the `route-changed` event that is dispatched by the router component itself, which is illustrated in the next section below.\n\nIn the rare case you would like to push a new state or change the current location without triggering a new route, you\ncan pass `triggerRouteChange` flag like this:\n\n```javascript\nwindow.history.pushState({ triggerRouteChange: false }, null, '/new-url');\n```\n\nRouter will clean up the `triggerRouteChange` property in `history.state`, so you don't need to worry about clearing it out.\n\n### Detecting Route Changes\n\nYou can listen to route changes that are triggered either by link clicks or via `History`'s [pushState()](http://w3c.github.io/html/browsers.html#dom-history-pushstate) or replaceState API\n\n```html\n\u003chtml\u003e\n    \u003chead\u003e\n        \u003cscript\n            type=\"module\"\n            src=\"node_modules/router-component/dist/router-component.js\"\n        \u003e\u003c/script\u003e\n        \u003cscript type=\"module\"\u003e\n            const router = document.body.querySelector('router-component');\n            router.addEventListener('route-changed', () =\u003e {\n                // called everytime the route changes!\n            });\n        \u003c/script\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n        \u003crouter-component\u003e\n            \u003cother-page path=\"/other[/]?\"\u003e\u003c/other-page\u003e\n            \u003cfallback-page path=\".*\"\u003e\u003c/fallback-page\u003e\n        \u003c/router-component\u003e\n    \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Development\n\nTo run tests:\n\n```bash\nnpm test\n```\n\nTo debug and run locally:\n\n```bash\nnpm start\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkcellus%2Frouter-component","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkcellus%2Frouter-component","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkcellus%2Frouter-component/lists"}