Vertical navigation with a line marker that expands on hover and active state. Inspired by Devouring Details and Skiper UI.
Preview
Usage
Installation
$ pnpm dlx shadcn add https://infinityui.vercel.app/r/line-nav.json
Basic Example
"use client"
import React, { useState } from "react"
import { LineNav } from "@/components/line-nav"
export default function LineNavDemo() {
const [activeHref, setActiveHref] = useState("#elastic-slider")
return (
<LineNav
className="w-60"
items={ITEMS}
activeHref={activeHref}
scrollActiveIntoView={false}
onItemClick={(item) => setActiveHref(item.href)}
/>
)
}
const ITEMS = [
{ title: "Apple Hello Effect", href: "#apple-hello-effect" },
{ title: "Code Block Command", href: "#code-block-command" },
{ title: "Copy Button", href: "#copy-button" },
{ title: "Dot Grid Spotlight", href: "#dot-grid-spotlight" },
{ title: "Elastic Slider", href: "#elastic-slider" },
{ title: "Fluid Gradient Text", href: "#fluid-gradient-text" },
{ title: "Shimmering Text", href: "#shimmering-text" },
{ title: "Slide to Unlock", href: "#slide-to-unlock" },
{ title: "Theme Switcher", href: "#theme-switcher" },
{ title: "TOC Minimap", href: "#toc-minimap" },
]
Features
- Expanding Marker: The active item's line marker expands and its label brightens to mark the current page.
- Scroll Alignment: The active item scrolls into view on mount, staying visible in long lists.
- Dynamic Springs: Uses spring physics for smooth width adjustments.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
items | LineNavItem[] | — | The array of navigation items, each with a title and href. |
activeHref | string | — | The href of the active navigation item. |
scrollActiveIntoView | boolean | true | Scroll the active item into view on mount. |
onItemClick | (item: LineNavItem, event: React.MouseEvent) => void | — | Callback function invoked when a navigation item is clicked. |
className | string | — | Additional CSS classes for the container element. |
Examples
Client-side navigation
Items render as plain anchors to stay framework-agnostic. For client-side navigation in Next.js (or React Router), edit the source and render the item through a router link instead:
+ import Link from "next/link"
import { motion } from "motion/react"
+ const MotionLink = motion.create(Link)
- <motion.a
+ <MotionLink
ref={ref}
href={href}
initial={false}
animate={active ? "active" : "normal"}
whileHover="hover"
onClick={onClick}
>
{/* ... */}
- </motion.a>
+ </MotionLink>