Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Hooks & Utilities

Navigation

Hooks & Utilities

Navigation TypeScript helper for React

Motion presetsNumber format
Live props
Provider
currentPath
Matching
match
  1. Home
  2. Components
  3. Hooks & Utilities
  4. Navigation
Free

Navigation TypeScript helper for React

v1.0.0·Added in 1.0.0

Router-agnostic links, active-route matching, one NavItem shape and the app shell context that every nav component shares.

Click through the mini CRM: every link goes through a pretend router given to LinkProvider, the address bar updates and the matching item lights up with aria-current. Open a customer and Customers stays active by prefix; switch match to exact and it lets go. The external link opens a new tab and the disabled one ignores clicks and Tab.

Navigation is a free React helper in the React hooks and utilities category, written in TypeScript for React 19. It installs as source with npx wingo-ui@latest add navigation.

Add to a project

Requirements: React 19, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add navigation

Usage

Import NavLink from @/lib/navigation.

"use client"

import type { ReactNode } from "react"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { LinkProvider, matchPath, NavLink, useCurrentPath } from "@/lib/navigation"

// app/providers.tsx, rendered by the root layout around {children}
export function Providers({ children }: { children: ReactNode }) {
  return (
    <LinkProvider component={Link} currentPath={usePathname()}>
      {children}
    </LinkProvider>
  )
}

// any link inside renders through next/link and knows when it is the current page
export function ClientsLink() {
  const currentPath = useCurrentPath()
  return (
    <NavLink href="/customers" active={matchPath("/customers", currentPath)} className="data-active:font-semibold">
      Customers
    </NavLink>
  )
}

API

  • currentPathdefault ""
    string

    LinkProvider({ component, currentPath, onNavigate }): the current pathname (next: usePathname()). Every nav component inside finds its active item from it; a component's own currentPath or value prop wins.

  • componentdefault "a"
    ComponentType<LinkComponentProps> | "a"

    LinkProvider: the router link every NavLink renders through (next/link's Link, react-router's Link). Set it once in a client providers file; library components never import next/*.

  • onNavigate
    (href: string) => void

    LinkProvider: runs when a NavLink starts an in-app navigation (a plain left click on an internal link). useNavigateListener subscribes to the same event, which is how a route progress bar starts on its own.

  • navigate
    (href: string) => void

    LinkProvider: the router's push (next: useRouter().push). useNavigate() uses it for navigations without an anchor, like a command menu item picked with Enter; without it they fall back to a full page load.

  • matchdefault "prefix"
    "prefix" | "exact"

    matchPath(href, currentPath, match) and NavItem.match: prefix keeps /customers active on /customers/42, exact only on /customers. "/" always matches exactly.

  • NavLink
    ({ href, component?, active?, current?, disabled?, external?, ...anchorProps }) => JSX.Element

    An anchor through the router link: aria-current (current: "page" | "step" | "location") and data-active while active, a real disabled state (no href, aria-disabled, tabIndex -1), and external links (absolute urls to another origin, or external) in a new tab with rel="noopener noreferrer". data-slot="nav-link".

Parts

  • NavItem

    type

    One shape for sidebar, bottom tab bar, nav tabs, nav menu and the command menu, so an app defines its navigation once. navItemKey(item) is id, else href, else a string label. Type: { id?, label, textValue?, href?, icon?, activeIcon?, badge?, description?, disabled?, external?, match?, onSelect?, items?, keywords?, shortcut? }.

  • NavGroup

    type

    One shape for sidebar, bottom tab bar, nav tabs, nav menu and the command menu, so an app defines its navigation once. navItemKey(item) is id, else href, else a string label. Type: { id?, label?, items, collapsible?, defaultOpen? }.

  • findActivePath

    function

    The active item and its ancestors ([Settings, Team]): an explicit value (an item key) wins, else the most specific href match. Pass groupItems(groups) for grouped navigation. flattenNavItems, navItemText, isExternalHref and normalizePath are exported too. Signature: (items: NavItem[], { value?, currentPath? }) => NavItem[] | null.

  • useLinkComponent

    hook

    For component authors: the provider's link component and path with a prop override, a subscription to in-app navigations, and a navigate function (external urls open in a new tab, in-app paths notify listeners and go through the provider's navigate). Signature: (override?) => LinkComponent.

  • useCurrentPath

    hook

    For component authors: the provider's link component and path with a prop override, a subscription to in-app navigations, and a navigate function (external urls open in a new tab, in-app paths notify listeners and go through the provider's navigate). Signature: (override?) => string | undefined.

  • useNavigateListener

    hook

    For component authors: the provider's link component and path with a prop override, a subscription to in-app navigations, and a navigate function (external urls open in a new tab, in-app paths notify listeners and go through the provider's navigate). Signature: (listener) => void.

  • useNavigate

    hook

    For component authors: the provider's link component and path with a prop override, a subscription to in-app navigations, and a navigate function (external urls open in a new tab, in-app paths notify listeners and go through the provider's navigate). Signature: () => (href, { external? }) => void.

  • NavShellProvider

    component

    What an app shell shares with the bars inside it: isMobile, collapsed and setCollapsed, mobileOpen and setMobileOpen, toggleSidebar, hasSidebar, scroll (window or content) and its labels. A top bar renders the menu button from it and a tab bar knows the shell lays it out, without importing the shell. Props: ({ value: NavShellState, children }).

  • useNavShell

    hook

    What an app shell shares with the bars inside it: isMobile, collapsed and setCollapsed, mobileOpen and setMobileOpen, toggleSidebar, hasSidebar, scroll (window or content) and its labels. A top bar renders the menu button from it and a tab bar knows the shell lays it out, without importing the shell. Signature: () => NavShellState | null.

Examples

Settings tabs

Links in a tab bar with exact matching, so General is not active on /settings/billing. Swap DemoLink for next/link in an app.

Dependencies

No dependencies beyond React.

Files

  • lib/navigation.tsx

FAQ

Is the Navigation helper free?

Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.

How do I install Navigation?

Run npx wingo-ui@latest add navigation. With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/navigation.json.

See also

useMediaQueryhookuseShortcuthookuseScrollStatehook

Used in

Listing cardHero HeaderBottom Tab BarLogin PageMarketplace Home PageMobile App HomeOrder trackerUser MenuNav MenuSidebarApp ShellReviews

and 116 more.

More React hooks and utilities

Number formatlibRelative timelibRomanian locationslibSpreadsheetlibText matchlibToneslib
All 36 React hooks and utilities
PreviousMotion presetsNext Number format
crm.example.com/customers/42
onNavigate × 0
Home
Customers
Deals
Invoices
SettingsProfileTeam
  1. Customers
  2. Northwind Tech LLC

Northwind Tech LLC

Customer in New York · 12 invoices · balance $12,480.00

matchPath("/customers", "/customers/42", "prefix") = true

DocumentationReports · coming soon