Nav Menu
nexvyn/nav-menuFreeComponent
A vertical navigation list with two-layer proximity highlight (active route + hover), weight-shift labels, and status dots for new/updated items.
Live preview
live · rendered by the registry
Rendered by nexvyn on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.nexvyn.dev/r/nav-menu.jsonSource
1'use client'23import {4 cloneElement,5 createContext,6 forwardRef,7 isValidElement,8 useCallback,9 useContext,10 useEffect,11 useMemo,12 useRef,13 type HTMLAttributes,14 type ReactNode,15} from 'react'16import { Slot } from '@radix-ui/react-slot'17import { motion, useMotionValue, useReducedMotion, useSpring, type MotionValue } from 'motion/react'18import { cn } from '@/lib/utils'19import { springs } from '@/lib/motion-tokens'20import {21 useProximityHighlight,22 ProximityHighlight,23 type ItemRect,24} from '@/lib/hooks/use-proximity-highlight'25import { WeightShiftText } from '@/components/ui/weight-shift-text'2627interface NavMenuContextValue {28 activeSlug: string | null29 nextIndex: () => number30 registerItem: (index: number, el: HTMLElement | null) => void31}3233const NavMenuContext = createContext<NavMenuContextValue | null>(null)3435function useNavMenuCtx(componentName: string) {36 const ctx = useContext(NavMenuContext)37 if (!ctx) throw new Error(`${componentName} must be used within NavMenu`)38 return ctx39}4041interface NavMenuContentContextValue {42 activeIndex: number | null43 setActiveIndex: (i: number | null) => void44 highlightX: ReturnType<typeof import('motion/react').useSpring>45 highlightSize: MotionValue<number>46 highlightOpacity: ReturnType<typeof import('motion/react').useSpring>47 axis: 'x' | 'y'48 registerItem: (index: number, el: HTMLElement | null) => void49}5051const NavMenuContentContext = createContext<NavMenuContentContextValue | null>(null)5253function useNavMenuContentCtx(componentName: string) {54 const ctx = useContext(NavMenuContentContext)55 if (!ctx) throw new Error(`${componentName} must be used within NavMenuContent`)56 return ctx57}5859export interface NavMenuProps extends HTMLAttributes<HTMLElement> {60 children: ReactNode61 activeSlug: string | null62 'aria-label'?: string63}6465export const NavMenu = forwardRef<HTMLElement, NavMenuProps>(66 ({ children, activeSlug, 'aria-label': ariaLabel = 'Main', className, ...props }, ref) => {67 const navRef = useRef<HTMLElement>(null)68 const activeItemRectRef = useRef<ItemRect | null>(null)6970 const {71 activeIndex,72 setActiveIndex,73 registerItem,74 handlers,75 highlightX,76 highlightSize,77 highlightOpacity,78 axis,79 } = useProximityHighlight(navRef, { axis: 'y' })8081 const indexRef = useRef(0)82 const nextIndex = useCallback(() => {83 const idx = indexRef.current84 indexRef.current += 185 return idx86 }, [])8788// … truncated
What it pulls in
npm packages
Files it writes
More from nexvyn
All 40 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | nexvyn | Components | Free | 1 dep | |
| Action Buttonaction-button | nexvyn | Components | Free | 3 deps · 4 files | |
| Adaptive Actionsadaptive-actions | nexvyn | Components | Free | 1 dep | |
| AI Inputai-input | nexvyn | Components | Free | 1 dep · 2 files | |
| Badgebadge | nexvyn | Components | Free | 2 deps · 2 files | |
| Bars Themebars-theme | nexvyn | Components | Free | 1 dep · 3 files | |
| Bounce Sidebarbounce-sidebar | nexvyn | Components | Free | 1 dep · 2 files | |
| Breadcrumbsbreadcrumbs | nexvyn | Components | Free | 1 dep · 2 files |
