Preact-router Link activeClassName is not applied when changing page

159 Views Asked by At

Im working on a small project and I do not get the expected behavior from preact-router, Link. It either doesnt change the page or it doesnt set the activeClassName, depending on where I import it from.

Given the following code

<main>
    <nav>
        <Link href="/" activeClassName="active-link">Home</Link>
        <Link href="/someOtherPage" activeClassName="active-link">SomeOtherPage</Link>
    </nav>
    <Router>
        <Route path="/" component={Home} />
        <Route path="/someOtherPage" component={SomeOtherPage} />
    </Router>
</main>

I get different behaviour depending on where I import Link from.

import { Link } from "preact-router"; With this the pages change when clicking the links however the css class .active-linkis not applied.

import { Link } from "preact-router/match"; This gives me the opposite result. The activeClassName changes correctly, however the page does not change.

Obviously I want it to both change the pages correctly and assign the active class to the active link. Which is what I thought it would do by default.

I found a solution which works, but it seems more complicated than what I thought it would be. Also it doesnt show the correct active link if you go back one page.

import { Router, Route, Link, getCurrentUrl } from "preact-router";
import { useRef } from "preact/hooks"; 
import { QueryClient, QueryClientProvider } from "react-query";

import "./styles/app.css";

const queryClient = new QueryClient();

const App = () => {
    const nav = useRef(null);

    const switchClass = (event) => {
        for (const link of nav.current.children)
            link.className = null;
        event.target.className = "active-link";
    }

    const currentPath = getCurrentUrl();

    return (
        <QueryClientProvider client={queryClient}>
            <main>
                <nav ref={nav}>
                    <Link href="/" className={currentPath === "/" ? "active-link" : null} onClick={switchClass}>Home</Link>
                    <Link href="/" className={currentPath === "/someOtherPage" ? "active-link" : null} onClick={switchClass}>SomeOtherPage</Link>
                </nav>
                <Router>
                    <Route path="/" component={Home} />
                    <Route path="/someOtherPage" component={SomeOtherPage} />
                </Router>
            </main>
        </QueryClientProvider>
    );
}
1

There are 1 best solutions below

2
On

import { Link } from "preact-router"; With this the pages change when clicking the links however the css class .active-link is not applied.

It's not supposed to. To quote the docs:

preact-router includes an add-on module called match that lets you wire your components up to Router changes.

...

<Link> is just a normal link, but it automatically adds and removes an "active" classname to itself based on whether it matches the current URL.

Only when importing from preact-router/match will you get active class matching.

import { Link } from "preact-router/match"; This gives me the opposite result. The activeClassName changes correctly, however the page does not change.

This sounds like a bug in your code, though without a full example, I cannot reproduce.

I created an interactive StackBlitz example for you here that you can play around with it, but the code more or less looks like this:

import { Router, Route } from 'preact-router';
import { Link } from 'preact-router/match';

...

export function App() {
  return (
    <main>
      <nav>
        <Link href="/" activeClassName="active-link">
          Home
        </Link>
        <Link href="/someOtherPage" activeClassName="active-link">
          SomeOtherPage
        </Link>
      </nav>
      <Router>
        <Route path="/" component={Home} />
        <Route path="/someOtherPage" component={SomeOtherPage} />
      </Router>
    </main>
  );
}

If that's not routing for you, you have an issue in your framework and/or tooling.