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 🙏

© 2026 – Pkg Stats / Ryan Hefner

ripple-router-dom

v1.0.0

Published

Declarative routing for RippleJS

Readme

ripple-router-dom

npm version License: MIT

Declarative routing for RippleJS

A simple, lightweight, and fully reactive routing library for RippleJS applications. Inspired by the excellent API of react-router-dom.

Installation

npm install ripple-router-dom

Note: Requires ripple as a peer dependency

Quick Start

import { Router, Route, Link } from 'ripple-router-dom';

component Home() {
    <div>
        <h1>{"Home Page"}</h1>
    </div>
}

component About() {
    <div>
        <h1>{"About Page"}</h1>
    </div>
}

export component App() {
    <Router>
        <nav>
            <Link to="/">{"Home"}</Link>
            <Link to="/about">{"About"}</Link>
        </nav>

        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
    </Router>
}

API Reference

Components

<Router>

The root component that manages navigation state. Wrap your entire app or routing section.

<Router>
    {/* Your routes and navigation */}
</Router>

Props:

  • children: Component - Child components (routes, links, etc.)

<Route>

Renders a component when the current location matches the specified path.

<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/user/:id" component={UserProfile} />

Props:

  • path: string - Path pattern to match (supports dynamic params with :param)
  • component: Component - Component to render when matched
  • exact?: boolean - Whether to match exactly (default: true)

Dynamic Parameters:

Use :paramName syntax for dynamic route segments:

<Route path="/user/:id" component={User} />
<Route path="/blog/:category/:slug" component={BlogPost} />

Access parameters using useRouter():

component User() {
    const router = useRouter();
    const userId = [email protected];

    <div>
        <h1>{"User Profile"}</h1>
        <p>{`User ID: ${userId}`}</p>
    </div>
}

<Link>

Creates a navigation link that doesn't reload the page.

<Link to="/">{"Home"}</Link>
<Link to="/about" class="nav-link" activeClass="active">
    {"About"}
</Link>

Props:

  • to: string - Destination path
  • children: Component - Link content
  • class?: string - CSS classes for the link
  • activeClass?: string - CSS class added when link is active (default: "active")

Active Link Styling:

The activeClass is automatically applied when the current path matches the link's to prop:

<style>
    a.active {
        font-weight: bold;
        color: blue;
    }
</style>

<Link to="/" activeClass="active">{"Home"}</Link>

<Navigate>

Component for programmatic redirects. Executes navigation on mount.

if (!isAuthenticated) {
    <Navigate to="/login" />
}

// With replace (doesn't add to history)
<Navigate to="/dashboard" replace={true} />

Props:

  • to: string - Destination path
  • replace?: boolean - Replace current history entry instead of pushing (default: false)

Functions & Hooks

navigate(path: string)

Function for programmatic navigation.

import { navigate } from 'ripple-router-dom';

<button onClick={() => navigate('/dashboard')}>
    {"Go to Dashboard"}
</button>

useRouter()

Hook to access the router context in components.

import { useRouter } from 'ripple-router-dom';

component UserProfile() {
    const router = useRouter();

    // Access current pathname
    const currentPath = router.@pathname;

    // Access route parameters
    const userId = [email protected];

    <div>
        <p>{`Current path: ${currentPath}`}</p>
        <p>{`User ID: ${userId}`}</p>
    </div>
}

Returns:

{
    pathname: Tracked<string>,  // Current pathname (reactive)
    params: Tracked<Record<string, string>>  // Route params (reactive)
}

📖 Examples

Basic Routing

import { Router, Route, Link } from 'ripple-router-dom';

component Home() {
    <div>
        <h1>{"Home"}</h1>
        <p>{"Welcome to the home page!"}</p>
    </div>
}

component About() {
    <div>
        <h1>{"About"}</h1>
        <p>{"Learn more about us."}</p>
    </div>
}

export component App() {
    <Router>
        <nav>
            <Link to="/">{"Home"}</Link>
            {" | "}
            <Link to="/about">{"About"}</Link>
        </nav>

        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
    </Router>
}

Dynamic Routes

import { Router, Route, Link, useRouter } from 'ripple-router-dom';

component UserProfile() {
    const router = useRouter();
    const userId = [email protected];

    <div>
        <h1>{"User Profile"}</h1>
        <p>{`Viewing profile for user: ${userId}`}</p>
    </div>
}

export component App() {
    <Router>
        <nav>
            <Link to="/user/123">{"User 123"}</Link>
            <Link to="/user/456">{"User 456"}</Link>
        </nav>

        <Route path="/user/:id" component={UserProfile} />
    </Router>
}

Programmatic Navigation

import { Router, Route, navigate } from 'ripple-router-dom';
import { track } from 'ripple';

component LoginForm() {
    let username = track('');
    let password = track('');

    const handleSubmit = () => {
        // Simulate login
        if (@username && @password) {
            navigate('/dashboard');
        }
    };

    <div>
        <h2>{"Login"}</h2>
        <input
            type="text"
            value={@username}
            onInput={(e) => @username = e.target.value}
            placeholder="Username"
        />
        <input
            type="password"
            value={@password}
            onInput={(e) => @password = e.target.value}
            placeholder="Password"
        />
        <button onClick={handleSubmit}>{"Login"}</button>
    </div>
}

component Dashboard() {
    <div>
        <h1>{"Dashboard"}</h1>
        <button onClick={() => navigate('/')}>{"Logout"}</button>
    </div>
}

export component App() {
    <Router>
        <Route path="/" component={LoginForm} />
        <Route path="/dashboard" component={Dashboard} />
    </Router>
}

Protected Routes

import { Router, Route, Navigate } from 'ripple-router-dom';
import { track } from 'ripple';

component ProtectedPage() {
    let isAuthenticated = track(false); // Replace with real auth logic

    if (!@isAuthenticated) {
        <Navigate to="/login" />
    }

    <div>
        <h1>{"Protected Content"}</h1>
        <p>{"You can only see this if authenticated"}</p>
    </div>
}

export component App() {
    <Router>
        <Route path="/protected" component={ProtectedPage} />
        <Route path="/login" component={LoginForm} />
    </Router>
}

Active Link Styling

import { Router, Route, Link } from 'ripple-router-dom';

component Navigation() {
    <style>
        nav {
            display: flex;
            gap: 20px;
            padding: 20px;
            background: #f0f0f0;
        }

        a {
            text-decoration: none;
            color: #333;
            padding: 10px 15px;
            border-radius: 4px;
            transition: all 0.2s;
        }

        a.active {
            background: #007bff;
            color: white;
            font-weight: bold;
        }

        a:hover {
            background: #e0e0e0;
        }

        a.active:hover {
            background: #0056b3;
        }
    </style>

    <nav>
        <Link to="/" activeClass="active">{"Home"}</Link>
        <Link to="/about" activeClass="active">{"About"}</Link>
        <Link to="/contact" activeClass="active">{"Contact"}</Link>
    </nav>
}

export component App() {
    <Router>
        <Navigation />
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
    </Router>
}

🛣️ Roadmap

  • [ ] Query parameter support (?key=value)
  • [ ] Wildcard routes (*)
  • [ ] 404 / fallback routes
  • [ ] Lazy loading
  • [ ] Better nested routes
  • [ ] Scroll restoration
  • [ ] Hash routing mode

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT © Dilgo-dev

🙏 Acknowledgments


Enjoy routing with Ripple! 🌊