npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2025 – Pkg Stats / Ryan Hefner

@zessjs/router

v1.1.6

Published

Zess router πŸ“ Client-side navigation, dynamic & nested routing for web apps

Readme

NPM Version NPM License

Zess router πŸ“ Client-side navigation, dynamic & nested routing for web apps.

✨ Features

  • 🎯 Simple and Lightweight: Easy-to-use API with minimal configuration required
  • ⚑ Performance Optimized: Caches each route component for excellent rendering performance
  • πŸ”„ Multiple Modes: Supports both hash mode and history mode for different deployment environments
  • 🧩 Nested Routes: Create complex route hierarchies with nested components
  • πŸš€ Dynamic Navigation: Programmatically navigate between routes using hooks
  • πŸ” Search Params Handling: Built-in support for managing query parameters
  • πŸ”’ Type Safety: Complete TypeScript type definitions
  • πŸ”„ Seamless Integration: Works perfectly with @zessjs/core reactive system

πŸ“¦ Installation

# Using npm
npm install @zessjs/router

# Using yarn
yarn add @zessjs/router

# Using pnpm
pnpm add @zessjs/router

πŸš€ Basic Usage

Setting Up the Router

import { render } from '@zessjs/core'
import { Router, Route } from '@zessjs/router'

function RootLayout(props) {
  return <div>{props.children}</div>
}

function HomePage() {
  return <h1>Welcome to Home Page</h1>
}

function AboutPage() {
  return <h1>About Us</h1>
}

render(
  () => (
    <Router root={RootLayout}>
      <Route path="/" component={HomePage} />
      <Route path="/about" component={AboutPage} />
    </Router>
  ),
  document.getElementById('app'),
)

Using Navigation Links

import { Link } from '@zessjs/router'

function Navigation() {
  return (
    <nav>
      <Link to="/" class="nav-link">
        Home
      </Link>
      <Link to="/about" class="nav-link">
        About
      </Link>
    </nav>
  )
}

Programmatically Navigating

import { useNavigate } from '@zessjs/router'

function NavigationButtons() {
  const navigate = useNavigate()

  return (
    <div>
      <button onClick={() => navigate('/')}>Go to Home</button>
      <button onClick={() => navigate('/about', { replace: true })}>
        Go to About
      </button>
    </div>
  )
}

πŸ”§ Advanced Usage

Nested Routes

import { Router, Route } from '@zessjs/router'

function AppLayout(props) {
  return (
    <div class="app">
      <header>Zess Application</header>
      <main>{props.children}</main>
    </div>
  )
}

function UserLayout(props) {
  return (
    <div class="user-section">
      <nav class="user-nav">User Navigation</nav>
      <div class="user-content">{props.children}</div>
    </div>
  )
}

function HomePage() {
  return <h1>Welcome to Home Page</h1>
}

function UserList() {
  return <h2>User List</h2>
}

function UserProfile() {
  return <h2>User Profile</h2>
}

render(
  () => (
    <Router root={AppLayout}>
      <Route path="/" component={HomePage} />
      {/* Nested routes */}
      <Route path="/users" component={UserLayout}>
        <Route path="/" component={UserList} />
        <Route path="/profile" component={UserProfile} />
      </Route>
    </Router>
  ),
  document.getElementById('app'),
)

Working with Search Parameters

import { useSearchParams } from '@zessjs/router'

function SearchComponent() {
  const [searchParams, setSearchParams] = useSearchParams()
  const handleSearch = (event) => {
    event.preventDefault()
    const formData = new FormData(event.target)
    const query = formData.get('query')
    setSearchParams({ query })
  }

  return (
    <div>
      <form onSubmit={handleSearch}>
        <input type="text" name="query" defaultValue={searchParams.query} />
        <button type="submit">Search</button>
      </form>
      {searchParams.query && <p>Searching for: {searchParams.query}</p>}
    </div>
  )
}

Using Different Router Modes

// Hash mode (default)
render(
  () => (
    <Router mode="hash" root={RootLayout}>
      <Route path="/" component={HomePage} />
    </Router>
  ),
  document.getElementById('app'),
)

// History mode
render(
  () => (
    <Router mode="history" root={RootLayout}>
      <Route path="/" component={HomePage} />
    </Router>
  ),
  document.getElementById('app'),
)

πŸ“š API Reference

Components

Router(props: RouterProps): JSX.Element

The main router component that wraps all your routes and provides the routing context.

Parameters:

  • mode: Optional routing mode, either 'hash' or 'history'. Defaults to 'hash'
  • root: Optional component that wraps the rendered component for all routes
  • children: <Route> components to be rendered

Example:

<Router mode="hash" root={RootLayout}>
  <Route path="/" component={HomePage} />
  <Route path="/about" component={AboutPage} />
</Router>

Route(props: RouteProps): JSX.Element

Defines a route and its corresponding component.

Parameters:

  • path: The path pattern for this route
  • sensitive: Optional flag to make the path matching case-sensitive. Defaults to false
  • component: Optional component to render when the route is matched
  • children: Optional nested <Route> components

Example:

// Basic route
<Route path="/about" component={AboutPage} />

// Case-sensitive route
<Route path="/API" sensitive component={ApiPage} />

// Route with nested routes
<Route path="/dashboard" component={DashboardLayout}>
  <Route path="/stats" component={StatsPage} />
  <Route path="/settings" component={SettingsPage} />
</Route>

// Wildcard route (matches any path)
<Route path="*" component={NotFoundPage} />

Link(props: LinkProps): JSX.Element

Creates a navigable link to another route.

Parameters:

  • to: The destination path, can include query strings
  • relative: Optional flag to navigate to the relative path. Defaults to true
  • replace: Optional flag to replace the current history entry instead of pushing a new one
  • noScroll: Optional flag to prevent scrolling to top when navigating
  • state: Optional state object to pass to history.state, defaults to null
  • style: Optional CSS styles
  • class: Optional CSS class name
  • activeClass: Optional CSS class name to apply when the link is active
  • end: Optional flag to match the path exactly. When set to true, the link will only be active if the current path matches exactly
  • children: Optional content for the link

Example:

// Basic link
<Link to="/home">Home</Link>

// Link with absolute path
<Link to="/about" relative={false}>About (Exact)</Link>

// Link with replace
<Link to="/login" replace>Login</Link>

// Link with noScroll
<Link to="/details" noScroll>View Details (No Scroll)</Link>

// Link with styles
<Link to="/contact" style={{ color: 'blue' }}>Contact</Link>

// Link with className
<Link to="/profile" class="user-link">Profile</Link>

// Link with activeClass
<Link to="/dashboard" activeClass="active-nav">Dashboard</Link>

// Link with end prop
<Link to="/settings" end>Settings (Exact Match)</Link>

// Link with query parameters
<Link to="/products?category=electronics&sort=price">Products (Electronics)</Link>

// Link with state
<Link to="/account" state={{ from: 'search', sourceId: 1 }}>
  View Product Details
</Link>

Primitives

useNavigate(): (href: string, options?: NavigateOptions) => void

Hook that returns a function to programmatically navigate between routes.

Returns: A function that accepts a path and optional navigation options

  • href: The destination path, can include query strings
  • options: Optional configuration
    • relative: If false, navigates to the absolute path without relative base. Defaults to true
    • replace: If true, replaces the current history entry
    • noScroll: If true, prevents scrolling to top when navigating
    • state: Optional state object to pass to history.state, defaults to null

Example:

function NavigationComponent() {
  const navigate = useNavigate()

  return (
    <>
      <button onClick={() => navigate('/')}>Home</button>
      <button onClick={() => navigate('/products', { relative: false })}>
        Products
      </button>
      <button onClick={() => navigate('/login', { replace: true })}>
        Login
      </button>
      <button onClick={() => navigate('/details', { noScroll: true })}>
        View Details (No Scroll)
      </button>
      <button onClick={() => navigate('/search?q=zess&page=1')}>
        Search Zess (Page 1)
      </button>
      <button onClick={() => navigate('/checkout', { state: { userId: 1 } })}>
        Proceed to Checkout
      </button>
    </>
  )
}

useSearchParams(): [SearchParams, (params: Record<string, any>, options?: SearchParamsOptions) => void]

Hook that provides access to search parameters and a function to update them.

Returns: An array containing

  • searchParams: A reactive object with current search parameters that auto-updates when location.search changes or when modified via setSearchParams
  • setSearchParams: A function to update search parameters
    • params: Search parameters to merge with existing ones. Setting a property value to undefined, null or an empty string removes that property
    • options: Optional configuration object
      • replace: Optional flag to replace the current history entry instead of pushing a new one
      • state: Optional state object to pass to history.state, defaults to null

Example:

function ProductFilter() {
  const [searchParams, setSearchParams] = useSearchParams()
  const setCategory = (category) => setSearchParams({ category })
  const search = (keyword, searchType) => {
    setSearchParams(
      { keyword },
      {
        replace: true,
        state: { searchType },
      },
    )
  }
  const clearFilters = () => {
    setSearchParams({ category: undefined, keyword: undefined })
  }

  return (
    <div>
      <p>Current category: {searchParams.category || 'All'}</p>
      <p>Search keyword: {searchParams.keyword || 'None'}</p>
      <button onClick={() => setCategory('shoes')}>Set Category</button>
      <button onClick={() => search('sale', 'quick')}>Search with Type</button>
      <button onClick={clearFilters}>Clear Filters</button>
    </div>
  )
}

useBeforeLeave(listener: RouteGuardListener): void

Hook that registers a listener to be called before leaving the current route. This allows you to intercept navigation attempts and potentially prevent them, for example, to warn users about unsaved changes.

Parameters:

  • listener: A function that will be called with a RouteGuardEvent object when navigation away from the current route is attempted
    • event: The route guard event object containing:
      • to: The destination path being navigated to
      • from: The current path being navigated from
      • options: Navigation options including relative, replace, and noScroll
      • defaultPrevented: Boolean indicating if the navigation has been prevented
      • preventDefault: Function to call to prevent the navigation
      • retry: Function to retry the navigation later, with an optional force parameter to bypass guards

Example:

function FormEditor() {
  const [hasUnsavedChanges, setHasUnsavedChanges] = useSignal(false)
  useBeforeLeave((event) => {
    if (hasUnsavedChanges()) {
      const confirmed = window.confirm(
        'You have unsaved changes. Are you sure you want to leave?',
      )
      if (!confirmed) {
        event.preventDefault()
      }
    }
  })

  return (
    <div>
      <input type="text" onChange={() => setHasUnsavedChanges(true)} />
      <button onClick={() => setHasUnsavedChanges(false)}>Save</button>
    </div>
  )
}

useLocation(): Location

Hook that returns a reactive Location object containing information about the current URL. This object automatically updates when the URL changes.

Returns: A reactive Location object with pathname and other properties

  • pathname: The path portion of the URL excluding the query string
  • search: The query string portion of the URL
  • hash: The hash portion of the URL including the # symbol
  • state: The state object associated with the current history entry passed via useNavigate or <Link> component
  • query: A reactive object containing all query parameters of the URL

Example:

function LocationDisplay() {
  const location = useLocation()

  return (
    <div>
      <h2>Current Location Information</h2>
      <p>pathname: {location.pathname}</p>
      <p>search: {location.search}</p>
      <p>hash: {location.hash}</p>
      <p>state: {JSON.stringify(location.state)}</p>
      <p>query: {JSON.stringify(location.query)}</p>
    </div>
  )
}

πŸ”„ Compatibility

The Zess router is compatible with:

  • Node.js >=18.12.0
  • Modern browsers (Chrome, Firefox, Safari, Edge)

πŸ“ License

MIT