import Link from './Link'; // our version of link
export default () => (
<header className="Header">
<nav>
<Link activeClassName="active" href="/">
<a className="some-other-class">Home</a>
</Link>
<Link activeClassName="active" href="/about">
<a>About</a>
</Link>
<Link activeClassName="active" href="/contact">
<a>Contact</a>
</Link>
</nav>
</header>
);
Last active
November 2, 2024 23:50
-
-
Save remy/0dde38897d6d660f0b63867c2344fb59 to your computer and use it in GitHub Desktop.
Next.js version of `activeClassName` support.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { withRouter } from 'next/router'; | |
import Link from 'next/link'; | |
import React, { Children } from 'react'; | |
const ActiveLink = ({ router, children, ...props }) => { | |
const child = Children.only(children); | |
let className = child.props.className || ''; | |
if (router.pathname === props.href && props.activeClassName) { | |
className = `${className} ${props.activeClassName}`.trim(); | |
} | |
delete props.activeClassName; | |
return <Link {...props}>{React.cloneElement(child, { className })}</Link>; | |
}; | |
export default withRouter(ActiveLink); |
typed. 21/10/22
Thank you very much remy san XD
import { withRouter, NextRouter } from 'next/router';
import React, { ReactElement } from 'react';
import Link from 'next/link';
type Props = {
router: NextRouter;
children: ReactElement;
href: string;
activeClassName: string;
}
const ActiveLink = ({ router, children, ...props }: Props) => {
const child = children;
let className: string = child.props.className;
if (router.pathname == props.href) {
className = `${className} ${props.activeClassName}`;
}
return (
<Link {...props}>{React.cloneElement(child, { className })}</Link>
);
}
export default withRouter(ActiveLink);
Here's my version of ActiveLink
for Next.js + TypeScript:
import Link, { LinkProps } from "next/link";
import { NextRouter, useRouter } from "next/router";
import { FC, PropsWithChildren } from "react";
type ActiveLinkProps = LinkProps & {
activeClassName: string;
className: string;
};
export const ActiveLink: FC<ActiveLinkProps> = ({ children, ...props }: PropsWithChildren<ActiveLinkProps>) => {
const router: NextRouter = useRouter();
const className: string =
props.className + ((router.pathname === props.href && props.activeClassName) ? " " + props.activeClassName : "");
return (
<Link {...props}>
<a className={className}>{children}</a>
</Link>
);
};
Example of usage:
<ActiveLink href="/" className="menulink" activeClassName="active">
Home
</ActiveLink>
The difference is you no longer need <a>
tag inside.
Benefits:
- TypeScript-friendly
- You no longer need to find child element and its type with
Children.only
- You no longer need to do
React.cloneElement
- You won't forget to put
<a>
inside anymore.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I rather have my own function that creates a pure
next/link
component:If you need a more reusable function, you can pass the router: