Skip to content

Commit

Permalink
Fix active link highlighting when using custom href formatting
Browse files Browse the repository at this point in the history
Previously when we formatted the `href` attribute (for example,
to prefix a `#` when using useHashLocation) this would make it
not match the current path, which would not have the hash prefix.

This patch preserves the target (href, or to) of the Link component
and then compares this value to the active path. This should then
match.

I have also altered some variable names to improve clarity given
we now have four different various 'paths' in this component.

Fixes #417
  • Loading branch information
neoeno authored and molefrog committed May 10, 2024
1 parent cf9ba61 commit 6677c50
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 5 deletions.
10 changes: 5 additions & 5 deletions packages/wouter/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ export const Route = ({ path, nest, match, ...renderProps }) => {

export const Link = forwardRef((props, ref) => {
const router = useRouter();
const [path, navigate] = useLocationFromRouter(router);
const [currentPath, navigate] = useLocationFromRouter(router);

const {
to,
href: _href = to,
href: targetPath = to,
onClick: _onClick,
asChild,
children,
Expand Down Expand Up @@ -219,13 +219,13 @@ export const Link = forwardRef((props, ref) => {
_onClick?.(event);
if (!event.defaultPrevented) {
event.preventDefault();
navigate(_href, props);
navigate(targetPath, props);
}
});

// handle nested routers and absolute paths
const href = router.hrefs(
_href[0] === "~" ? _href.slice(1) : router.base + _href,
targetPath[0] === "~" ? targetPath.slice(1) : router.base + targetPath,
router // pass router as a second argument for convinience
);

Expand All @@ -236,7 +236,7 @@ export const Link = forwardRef((props, ref) => {
onClick,
href,
// `className` can be a function to apply the class if this link is active
className: cls?.call ? cls(path === href) : cls,
className: cls?.call ? cls(currentPath === targetPath) : cls,
children,
ref,
});
Expand Down
28 changes: 28 additions & 0 deletions packages/wouter/test/link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,34 @@ describe("active links", () => {
expect(element).not.toHaveClass("active");
expect(element).toHaveClass("link");
});

it("correctly highlights active links when using custom href formatting", () => {
const formatter = (href: string) => `#${href}`;
const { navigate, hook } = memoryLocation({ path: "/" });

const { getByText } = render(
<Router hook={hook} hrefs={formatter}>
<Link
href="/"
className={(isActive) => {
return [isActive ? "active" : "", "link"].join(" ");
}}
>
Click Me
</Link>
</Router>
);

const element = getByText("Click Me");
expect(element).toBeInTheDocument();
expect(element).toHaveClass("active");
expect(element).toHaveClass("link");

act(() => navigate("/about"));

expect(element).not.toHaveClass("active");
expect(element).toHaveClass("link");
});
});

describe("<Link /> with `asChild` prop", () => {
Expand Down

0 comments on commit 6677c50

Please sign in to comment.