🚨 Active Supply Chain Attack:node-ipc Package Compromised.Learn More
Socket
Book a DemoSign in
Socket

@ecopages/browser-router

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ecopages/browser-router

Client-side router for Ecopages with view transitions support

latest
Source
npmnpm
Version
0.2.0-alpha.1
Version published
Weekly downloads
990
129.7%
Maintainers
1
Weekly downloads
 
Created
Source

@ecopages/browser-router

Client-side navigation and view transitions for Ecopages. Intercepts same-origin link clicks to provide smooth page transitions without full page reloads.

Features

  • Client-side navigation - Intercepts <a> clicks for fast navigation
  • Efficient DOM diffing - Uses morphdom to update only what changed, preserving scroll positions and internal state
  • State persistence - Elements with data-eco-persist are never recreated, preserving internal state
  • View Transitions - Optional integration with the View Transition API
  • Lifecycle events - Hook into navigation with eco:before-swap, eco:after-swap, eco:page-load

Compatibility

This 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.

Installation

bunx jsr add @ecopages/browser-router

Usage

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) causes morphdom to 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',
});

Configuration

OptionTypeDefaultDescription
linkSelectorstring'a[href]'Selector for links to intercept
persistAttributestring'data-eco-persist'Attribute to mark elements for DOM persistence
reloadAttributestring'data-eco-reload'Attribute to force full page reload
updateHistorybooleantrueWhether to update browser history
scrollBehavior'top' | 'preserve' | 'auto''top'Scroll behavior after navigation
viewTransitionsbooleanfalseUse View Transition API for animations
smoothScrollbooleanfalseUse smooth scrolling during navigation

Persistence

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>

Script Re-execution

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>

React islands with @ecopages/browser-router

When @ecopages/browser-router is used in an MPA-style app that also renders component-level React islands:

  • island hydration scripts may need to run again after eco:after-swap
  • hydration bootstraps should carry stable data-eco-script-id metadata
  • data-eco-rerun allows those bootstraps to be re-executed safely during head reconciliation

This 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.

Force Full Reload

Use data-eco-reload to force a full page reload:

<a href="/logout" data-eco-reload>Logout</a>

Events

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);
});

Programmatic Navigation

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 });

Keywords

ecopages

FAQs

Package last updated on 08 Mar 2026

Did you know?

Socket

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.

Install

Related posts