react-navplus
v2.1.0
Published
A flexible, performance-optimized navigation link component for React with multi-router support, prefetching, and advanced active state detection
Maintainers
Readme
NavPlus
A flexible, accessible, and framework-agnostic navigation link component for React.
Table of Contents
Features
- Active-state detection
exact,startsWith,includes, or custom regex (pattern)- Override with your own
isActiveFuncorcustomActiveUrl
- Prefetching support
- Hover-triggered prefetch with configurable delay
- Works with React Router, TanStack Router, Wouter, or your own custom prefetcher
- Flexible rendering
- Renders a React Router
<Link>, a plain<a>, a<span>, or any custom element viaas - Fully controllable redirection (
redirection), replace vs push (replace), and navigation delay
- Renders a React Router
- External & disabled links
isExternal→<a target="_blank" rel="noopener noreferrer">disabled→ renders a<span>witharia-disabled
- Styling & class names
className,activeClassName,inActiveClassNameactiveStyle,inactiveStyle
- Dynamic children
- Render static React nodes or pass a function
(isActive) => ReactNode
- Render static React nodes or pass a function
- Accessibility
- Custom ARIA attributes via
ariaprop - Automatically applies
aria-current="page"andaria-disabled
- Custom ARIA attributes via
- Test-friendly
data-testidsupport for easy querying in Jest, React Testing Library, Cypress, etc.
- Lightweight & Tree-shakable
- Written in TypeScript, no runtime dependencies beyond React
Installation
Using npm:
npm install react-navplusUsing Yarn:
yarn add react-navplusUsing Bun:
bun add react-navplusQuick Start
1. Basic Usage
import React from 'react';
import { NavPlus } from 'react-navplus';
const Nav = () => (
<nav>
<NavPlus to="/home">Home</NavPlus>
<NavPlus to="/about" matchMode="exact">
About
</NavPlus>
<NavPlus to="https://example.com" isExternal>
External Site
</NavPlus>
</nav>
);2. RouterNavLink Wrapper
If you’re using React Router v6, you can skip passing in location and navigate by using the built-in wrapper:
import React from 'react';
import { RouterNavLink } from 'react-navplus';
const Nav = () => (
<nav>
<RouterNavLink to="/dashboard" activeClassName="active">
Dashboard
</RouterNavLink>
</nav>
);3. Prefetch on Hover
<RouterNavLink
to="/products"
prefetch={{ enabled: true, delay: 150, routerType: 'tanstack-router' }}
>
Products
</RouterNavLink>4. Custom Rendering & Triggers
<RouterNavLink
to="/settings"
as="button"
triggerEvent="hover"
navigationDelay={300}
>
{(isActive) => (isActive ? <strong>Settings</strong> : <span>Settings</span>)}
</RouterNavLink>API
<NavPlus> Props
| Prop | Type | Default | Description |
| ------------------- | ---------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------- |
| to | string | — | Required. Target URL or path. |
| children | ReactNode | (isActive: boolean) => ReactNode | — | Content inside the link. Can be a React node or a render function that receives isActive. |
| location | { pathname: string } | undefined | Current location (e.g. from useLocation()). If omitted, link is never active. |
| navigate | (to: string, options?: { replace?: boolean }) => void | undefined | Navigation function (e.g. from useNavigate()). If omitted, behaves like a plain <a>. |
| matchMode | 'exact' | 'startsWith' | 'includes' | 'pattern' | 'includes' | How to match location.pathname against to (pattern uses matchPattern). |
| matchPattern | RegExp | undefined | Custom regex to match against current pathname (only when matchMode="pattern"). |
| customActiveUrl | string | undefined | Use a different URL for active detection instead of to. |
| isActiveFunc | (pathname: string, to: string) => boolean | undefined | Fully custom active-detection function. |
| prefetch | boolean | PrefetchOptions | false | Enable hover-prefetch. See PrefetchOptions below. |
| redirection | boolean | true | If false, renders a <span> and no navigation occurs. |
| replace | boolean | false | If true, navigation uses history.replace instead of push. |
| navigationDelay | number (ms) | undefined | Delay before performing navigation (useful for animations). |
| triggerEvent | 'click' | 'hover' | 'click' | Which event triggers navigation. |
| isExternal | boolean | false | Render as external link (<a target="_blank" rel="noopener noreferrer">). |
| disabled | boolean | false | Render as a disabled <span> with aria-disabled. |
| as | React.ElementType | undefined | Custom element or component to render instead of <Link>/<a>/<span>. |
| className | string | '' | Base class(es) applied to the link. |
| activeClassName | string | 'active' | Class applied when link is active. |
| inActiveClassName | string | '' | Class applied when link is not active. |
| activeStyle | React.CSSProperties | undefined | Inline style when active. |
| inactiveStyle | React.CSSProperties | undefined | Inline style when inactive. |
| id | string | undefined | id attribute on the rendered element. |
| aria | React.AriaAttributes | {} | Additional ARIA attributes. |
| testId | string | undefined | data-testid for automated tests. |
| linkProps | Omit<LinkProps, 'to' | 'replace'> | {} | Extra props to pass down when using React Router’s <Link>. |
| routerContext | any | undefined | Pass in your own router context ({ navigate, router }) for custom integrations. |
PrefetchOptions
interface PrefetchOptions {
enabled?: boolean; // default: true
delay?: number; // ms, default: 200
routerType?: 'react-router' | 'tanstack-router' | 'wouter' | 'custom'; // default: 'react-router'
customPrefetch?: (to: string) => void;
}Usage Tips
Custom matching: Use
matchMode="pattern" matchPattern={/^\/blog(\/|$)/}for advanced route matching.
Custom elements: Pass
as="button"or your own styled component to match your design system.Global context: The optional
NavContextinsrc/context/NavContext.tsxcan share navigation state or prefetch logic.Standalone hooks: We expose
useIsActiveandusePrefetchinsrc/hooks/if you need the logic outside of the component.
Contributing
- Fork the repo
- Create your feature branch (
git checkout -b feature/foo) - Commit your changes (
git commit -am 'Add foo') - Push to the branch (
git push origin feature/foo) - Open a Pull Request
Please run npm test and npm run lint before submitting.
License
MIT © [Your Name or Organization] See LICENSE for details.
