
Security News
Feross on TBPN: Socket's Series C and the State of Software Supply Chain Security
Feross Aboukhadijeh joins TBPN to discuss Socket's $60M Series C, 500%+ ARR growth, AI's impact on open source, and the rise in supply chain attacks.
@ecopages/browser-router
Advanced tools
Client-side router for Ecopages with view transitions support
Client-side navigation and view transitions for Ecopages. Intercepts same-origin link clicks to provide smooth page transitions without full page reloads.
<a> clicks for fast navigationdata-eco-persist are never recreated, preserving internal stateeco:before-swap, eco:after-swap, eco:page-loadThis package works with MPA-style rendering (KitaJS, Lit, vanilla JS) where the server returns full HTML pages.
Not compatible with React/Preact - These frameworks manage their own virtual DOM and component trees. Replacing the DOM breaks hydration, state, and event handlers. For React apps, use a framework-specific routing solution.
Component-level islands are a narrower case: small interactive roots emitted by another integration (for example a React island inside an otherwise MPA-style page) can work with @ecopages/browser-router, because ownership stays scoped to the island root instead of the full document.
bunx jsr add @ecopages/browser-router
Create and start the router in a global client-side script (e.g., src/layouts/base-layout.script.ts).
Important: Ensure the router script is injected in a consistent order within the
<head>across all pages. Inconsistent ordering (e.g. script between styles on one page but after on another) causesmorphdomto reload styles, leading to a "Flash of Unstyled Content" (FOUC).
import { createRouter } from '@ecopages/browser-router/client';
// Creates and starts the router with default options
const router = createRouter();
With custom options:
import { createRouter } from '@ecopages/browser-router/client';
const router = createRouter({
viewTransitions: true,
scrollBehavior: 'auto',
});
| Option | Type | Default | Description |
|---|---|---|---|
linkSelector | string | 'a[href]' | Selector for links to intercept |
persistAttribute | string | 'data-eco-persist' | Attribute to mark elements for DOM persistence |
reloadAttribute | string | 'data-eco-reload' | Attribute to force full page reload |
updateHistory | boolean | true | Whether to update browser history |
scrollBehavior | 'top' | 'preserve' | 'auto' | 'top' | Scroll behavior after navigation |
viewTransitions | boolean | false | Use View Transition API for animations |
smoothScroll | boolean | false | Use smooth scrolling during navigation |
Mark elements to preserve across navigations. These elements are never recreated during navigation, morphdom skips them entirely, preserving their internal state (event listeners, web component state, form values, etc.):
<!-- This counter keeps its state across all navigations -->
<radiant-counter data-eco-persist="counter"></radiant-counter>
To force a script to re-execute on every navigation (e.g. analytics, hydration), add data-eco-rerun and data-eco-script-id:
<script data-eco-rerun="true" data-eco-script-id="analytics">
// This runs on every navigation
trackPageview();
</script>
@ecopages/browser-routerWhen @ecopages/browser-router is used in an MPA-style app that also renders component-level React islands:
eco:after-swapdata-eco-script-id metadatadata-eco-rerun allows those bootstraps to be re-executed safely during head reconciliationThis note is specific to DOM-swapping navigation with @ecopages/browser-router. It does not apply to full React applications using @ecopages/react-router, where page routing and hydration are handled by the React router runtime itself.
Use data-eco-reload to force a full page reload:
<a href="/logout" data-eco-reload>Logout</a>
Listen to navigation lifecycle events:
document.addEventListener('eco:before-swap', (e) => {
console.log('Navigating to:', e.detail.url);
// Call e.detail.reload() to abort and do full reload
});
document.addEventListener('eco:after-swap', (e) => {
console.log('Swapped to:', e.detail.url);
});
document.addEventListener('eco:page-load', (e) => {
console.log('Page loaded:', e.detail.url);
});
import { createRouter } from '@ecopages/browser-router/client';
const router = createRouter();
// Navigate with pushState
await router.navigate('/new-page');
// Navigate with replaceState
await router.navigate('/new-page', { replace: true });
FAQs
Client-side router for Ecopages with view transitions support
We found that @ecopages/browser-router demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Feross Aboukhadijeh joins TBPN to discuss Socket's $60M Series C, 500%+ ARR growth, AI's impact on open source, and the rise in supply chain attacks.

Security News
OSV withdrew 157 OSV malware reports after automated false positives incorrectly flagged trusted npm and PyPI packages, sending bad records into tools that rely on OSV data.

Research
/Security News
TrapDoor crypto stealer hits 36 malicious packages across npm, PyPI, and Crates.io, targeting crypto, DeFi, AI, and security developers.