{"id":22010470,"url":"https://github.com/virtualstate/navigation","last_synced_at":"2025-12-11T21:09:10.202Z","repository":{"id":44995478,"uuid":"440131695","full_name":"virtualstate/navigation","owner":"virtualstate","description":"Native JavaScript navigation [web api] implementation","archived":false,"fork":false,"pushed_at":"2025-10-10T23:01:46.000Z","size":1276,"stargazers_count":108,"open_issues_count":6,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-28T06:55:04.113Z","etag":null,"topics":["browser","deno","navigation","typescript"],"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/virtualstate.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE-OF-CONDUCT.md","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},"funding":{"github":"fabiancook"}},"created_at":"2021-12-20T10:37:25.000Z","updated_at":"2025-10-10T23:01:50.000Z","dependencies_parsed_at":"2024-05-09T23:28:28.536Z","dependency_job_id":"61f5df47-f943-47a2-b522-35286127252f","html_url":"https://github.com/virtualstate/navigation","commit_stats":null,"previous_names":["virtualstate/app-history"],"tags_count":81,"template":false,"template_full_name":null,"purl":"pkg:github/virtualstate/navigation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Fnavigation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Fnavigation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Fnavigation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Fnavigation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/virtualstate","download_url":"https://codeload.github.com/virtualstate/navigation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Fnavigation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27670234,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-11T02:00:11.302Z","response_time":56,"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":["browser","deno","navigation","typescript"],"created_at":"2024-11-30T02:13:11.247Z","updated_at":"2025-12-11T21:09:10.190Z","avatar_url":"https://github.com/virtualstate.png","language":"TypeScript","funding_links":["https://github.com/sponsors/fabiancook"],"categories":["TypeScript"],"sub_categories":[],"readme":"# `@virtualstate/navigation`\n\nNative JavaScript [navigation](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API) implementation \n\n[//]: # (badges)\n\n### Support\n\n ![Node.js supported](https://img.shields.io/badge/node-%3E%3D16.0.0-blue) ![Deno supported](https://img.shields.io/badge/deno-%3E%3D1.17.0-blue) ![Bun supported](https://img.shields.io/badge/bun-%3E%3D0.1.11-blue) ![Chromium supported](https://img.shields.io/badge/chromium-%3E%3D98.0.4695.0-blue) ![Webkit supported](https://img.shields.io/badge/webkit-%3E%3D15.4-blue) ![Firefox supported](https://img.shields.io/badge/firefox-%3E%3D94.0.1-blue)\n\n \u003cdetails\u003e\u003csummary\u003eTest Coverage\u003c/summary\u003e\n\n ![Web Platform Tests 139/306](https://img.shields.io/badge/Web%20Platform%20Tests-139%2F306-brightgreen) ![92.8%25 lines covered](https://img.shields.io/badge/lines-92.8%25-brightgreen) ![92.8%25 statements covered](https://img.shields.io/badge/statements-92.8%25-brightgreen) ![83.76%25 functions covered](https://img.shields.io/badge/functions-83.76%25-brightgreen) ![83.32%25 branches covered](https://img.shields.io/badge/branches-83.32%25-brightgreen) \n\n\u003c/details\u003e\n\n[//]: # (badges)\n\n## Install \n\n\n\u003cdetails\u003e\u003csummary\u003enpm / yarn / GitHub\u003c/summary\u003e\n\n\n- [Package Registry Link - GitHub](https://github.com/virtualstate/navigation/packages)\n- [Package Registry Link - npm](https://www.npmjs.com/package/@virtualstate/navigation)\n\n```\nnpm i --save @virtualstate/navigation\n```\n\n_Or_\n\n```\nyarn add @virtualstate/navigation\n```\n\nThen\n\n```typescript\nimport { Navigation } from \"@virtualstate/navigation\";\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eSkypack\u003c/summary\u003e\n\n- [Package Registry Link - Skypack](https://www.skypack.dev/view/@virtualstate/navigation)\n\n```typescript\nconst { Navigation } = await import(\"https://cdn.skypack.dev/@virtualstate/navigation\");\n```\n\n_Or_\n\n```typescript\nimport { Navigation } from \"https://cdn.skypack.dev/@virtualstate/navigation\";\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eimportmap\u003c/summary\u003e\n\n[`importmap` documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap)\n\n```html\n\u003cscript type=\"importmap\"\u003e\n    {  \n        \"imports\": {\n            \"@virtualstate/navigation\": \"https://cdn.skypack.dev/@virtualstate/navigation\"\n        }\n    }\n\u003c/script\u003e\n\u003cscript type=\"module\"\u003e\n    import { Navigation } from \"@virtualstate/navigation\"\n\u003c/script\u003e\n```\n\u003c/details\u003e\n\n## Usage\n\nSee the [MDN documentation for the Navigation API](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API) for in depth information on usage. \n\n\u003cdetails\u003e\u003csummary\u003eExamples\u003c/summary\u003e\n\n## Navigation\n\n```typescript\nimport { Navigation } from \"@virtualstate/navigation\";\n\nconst navigation = new Navigation();\n\n// Set initial url\nnavigation.navigate(\"/\");\n\nnavigation.navigate(\"/skipped\");\n\n// Use .finished to wait for the transition to complete\nawait navigation.navigate(\"/awaited\").finished;\n\n```\n\n## Waiting for events\n\n```typescript\nimport { Navigation } from \"@virtualstate/navigation\";\n\nconst navigation = new Navigation();\n\nnavigation.addEventListener(\"navigate\", async ({ destination, preventDefault }) =\u003e {\n    if (new URL(destination.url).pathname === \"/disallow\") {\n        preventDefault();\n    }\n});\n\nawait navigation.navigate(\"/allowed\").finished; // Resolves\nawait navigation.navigate(\"/disallow\").finished; // Rejects\n\n```\n\n## Transitions\n\n```typescript\nimport { Navigation } from \"@virtualstate/navigation\";\nimport { loadPhotoIntoCache } from \"./cache\";\n\nconst navigation = new Navigation();\n\nnavigation.addEventListener(\"navigate\", async ({ destination, intercept }) =\u003e {\n    intercept({\n        async handler() {\n            await loadPhotoIntoCache(destination.url)\n        }\n    });\n});\n```\n\n## URLPattern\n\nYou can match `destination.url` using [`URLPattern`](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API)\n\n```typescript\nimport {Navigation} from \"@virtualstate/navigation\";\nimport {URLPattern} from \"urlpattern-polyfill\";\n\nconst navigation = new Navigation();\n\nnavigation.addEventListener(\"navigate\", async ({destination, intercept}) =\u003e {\n    const pattern = new URLPattern({ pathname: \"/books/:id\" });\n    const match = pattern.exec(destination.url);\n    if (match) {\n        intercept({\n            handler: transition\n        });\n    }\n\n    async function transition() {\n        console.log(\"load book\", match.pathname.groups.id)\n    }\n});\n\nnavigation.navigate(\"/book/1\");\n```\n\n## State\n\n```typescript\n\nimport { Navigation } from \"@virtualstate/navigation\";\n\nconst navigation = new Navigation();\n\nnavigation.addEventListener(\"currententrychange\", () =\u003e {\n    console.log({ updatedState: navigation.currentEntry?.getState() });\n});\n\nawait navigation.updateCurrentEntry({\n    state: {\n        items: [\n            \"first\",\n            \"second\"\n        ],\n        index: 0\n    }\n}).finished;\n\nawait navigation.updateCurrentEntry({\n    state: {\n        ...navigation.currentEntry.getState(),\n        index: 1\n    }\n}).finished;\n```\n\u003c/details\u003e\n\n## Polyfill\n\nIf a global instance of the navigation API is not available, this will provide one, integrated into the History API if available. \n\n```typescript\nimport \"@virtualstate/navigation/polyfill\";\n\nawait window.navigation.navigate(\"/\").finished;\n\n// Or if within a window global scope, aka in a browser:\nawait navigation.navigate(\"/\").finished;\n```\n\n\u003cdetails\u003e\u003csummary\u003ePolyfill Global Window Types\u003c/summary\u003e\n\nSee [`@types/dom-navigation`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/dom-navigation/package.json) for a standardised type definition for the Navigation API\nwhich can be utilised alongside this polyfill.\n\n```bash\nyarn add --dev @types/dom-navigation\n```\n\nThis should then be included as a type in your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\n      \"dom-navigation\"\n    ]\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003ePolyfill Serializer\u003c/summary\u003e\n\nYou may want to set a custom serializer to store state in history\n\nThe default serializer is [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)\n\nIn the past, a [structured clone like serializer](https://www.npmjs.com/package/@ungap/structured-clone) was used. This may be useful for you if \nyou're using native types rather than just JSON compatible values.\n\nAn example of making use of a custom serializer with the polyfill:\n\n```typescript\nimport { setSerializer } from \"@virtualstate/navigation/polyfill\";\nimport { serialize, deserialize } from \"@ungap/structured-clone\";\n\nsetSerializer({\n    stringify(value) {\n        return serialize(value)\n    },\n    parse(value) {\n        return deserialize(value)\n    }\n});\n```\n\n\u003c/details\u003e\n\n### Polyfill Known Limitations \n\n- [Navigation by setting window.location does not trigger navigate event](https://github.com/virtualstate/navigation/issues/27)\n- [Normal page navigations are not intercepted (excluding navigation api \u0026 history made changes)](https://github.com/virtualstate/navigation/issues/26)\n\nPlease [create a new GitHub Issue if you find further limitations](https://github.com/virtualstate/navigation/issues)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvirtualstate%2Fnavigation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvirtualstate%2Fnavigation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvirtualstate%2Fnavigation/lists"}