A cross-browser solution for styled scroll areas: it relies on native scrolling for accessibility and performance while exposing parts (viewport, scrollbar, thumb, corner) for styling.
@radix-ui/react-navigation-menu
class-variance-authority lucide-react1'use client'
2
3import * as React from 'react'
4import Image from 'next/image'
5import Link from 'next/link'
6import {
7 BookOpen,
8 Globe,
9 LayoutGrid,
10 MessageSquare,
11 Server,
12 Zap,
13} from 'lucide-react'
14
15import { useIsMobile } from '@/hooks/use-mobile'
16import {
17 NavigationMenu,
18 NavigationMenuContent,
19 NavigationMenuItem,
20 NavigationMenuLink,
21 NavigationMenuList,
22 NavigationMenuTrigger,
23 navigationMenuTriggerStyle,
24} from '@/components/ui/navigation-menu'
25
26const features = [
27 {
28 title: 'Real-time Sync',
29 href: '/features/sync',
30 icon: <Zap className="text-secondary size-5" />,
31 description: 'Experience zero latency across all your devices.',
32 },
33 {
34 title: 'API Access',
35 href: '/features/api',
36 icon: <Server className="text-secondary size-5" />,
37 description: 'Integrate easily with our well-documented REST API.',
38 },
39 {
40 title: 'Global Reach',
41 href: '/features/global',
42 icon: <Globe className="text-secondary size-5" />,
43 description: 'Localize your application with multi-language support.',
44 },
45]
46
47const resources = [
48 {
49 title: 'Documentation',
50 href: '/docs',
51 icon: <BookOpen className="text-secondary size-5" />,
52 },
53 {
54 title: 'Example Blocks',
55 href: '/blocks',
56 icon: <LayoutGrid className="text-secondary size-5" />,
57 },
58 {
59 title: 'Support Center',
60 href: '/help',
61 icon: <MessageSquare className="text-secondary size-5" />,
62 },
63]
64
65export function UserFriendlyNavigationMenu() {
66 const isMobile = useIsMobile()
67
68 return (
69 <div className="-mb-1 h-82">
70 <NavigationMenu viewport={isMobile}>
71 <NavigationMenuList className="flex-wrap">
72 <NavigationMenuItem>
73 <NavigationMenuTrigger>
74 Getting Started
75 </NavigationMenuTrigger>
76 <NavigationMenuContent>
77 <ul className="grid gap-2 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
78 <li className="row-span-3">
79 <NavigationMenuLink asChild>
80 <a
81 href="/"
82 className="from-secondary/10 flex h-full w-full flex-col justify-end rounded-xl bg-linear-to-t to-transparent p-4 no-underline outline-hidden transition-all duration-200 select-none focus:shadow-md"
83 >
84 <div className="from-secondary bg-gradient-to-r to-transparent bg-clip-text text-3xl/7 font-bold text-transparent">
85 LOGO
86 </div>
87 <div className="text-primary mb-1 text-lg font-semibold sm:mt-2">
88 Your App Name
89 </div>
90 <p className="text-sm leading-tight">
91 Build beautiful, fast
92 applications with our framework.
93 </p>
94 </a>
95 </NavigationMenuLink>
96 </li>
97 <ListItem
98 href="/docs/tutorial"
99 title="Quick Start"
100 >
101 Get your first project running in minutes.
102 </ListItem>
103 <ListItem
104 href="/docs/installation"
105 title="Environment Setup"
106 >
107 Detailed instructions for setting up your
108 development environment.
109 </ListItem>
110 <ListItem
111 href="/docs/pricing"
112 title="Pricing Plans"
113 >
114 View our subscription tiers and features.
115 </ListItem>
116 </ul>
117 </NavigationMenuContent>
118 </NavigationMenuItem>
119
120 <NavigationMenuItem>
121 <NavigationMenuTrigger>
122 Platform Features
123 </NavigationMenuTrigger>
124 <NavigationMenuContent>
125 <ul className="grid gap-1 p-1 sm:w-96">
126 {features.map((feature) => (
127 <ListItemWithIcon
128 key={feature.title}
129 title={feature.title}
130 href={feature.href}
131 icon={feature.icon}
132 >
133 {feature.description}
134 </ListItemWithIcon>
135 ))}
136 </ul>
137 </NavigationMenuContent>
138 </NavigationMenuItem>
139
140 {/* --- Resources --- */}
141 <NavigationMenuItem className="hidden md:block">
142 <NavigationMenuTrigger>Resources</NavigationMenuTrigger>
143 <NavigationMenuContent>
144 <ul className="grid w-40 gap-1 p-1">
145 {resources.map((res) => (
146 <NavigationMenuLink asChild key={res.title}>
147 <Link
148 href={res.href}
149 className="hover:bg-secondary/10 flex items-center gap-2 rounded-xl p-2 transition-colors"
150 >
151 {res.icon}
152 <span className="text-primary font-medium">
153 {res.title}
154 </span>
155 </Link>
156 </NavigationMenuLink>
157 ))}
158 </ul>
159 </NavigationMenuContent>
160 </NavigationMenuItem>
161
162 {/* --- Blog --- */}
163 <NavigationMenuItem>
164 <NavigationMenuLink
165 asChild
166 className={navigationMenuTriggerStyle()}
167 >
168 <Link href="/blog">Blog</Link>
169 </NavigationMenuLink>
170 </NavigationMenuItem>
171 </NavigationMenuList>
172 </NavigationMenu>
173 </div>
174 )
175}
176
177/* --- Helper Components --- */
178function ListItem({
179 title,
180 children,
181 href,
182 ...props
183}: React.ComponentPropsWithoutRef<'li'> & { href: string }) {
184 return (
185 <li {...props}>
186 <NavigationMenuLink asChild>
187 <Link
188 href={href}
189 className="hover:bg-secondary/10 block space-y-1 rounded-xl p-3 leading-tight transition-colors select-none"
190 >
191 <div className="text-primary text-sm leading-none font-medium">
192 {title}
193 </div>
194 <p className="line-clamp-2 text-sm leading-snug">
195 {children}
196 </p>
197 </Link>
198 </NavigationMenuLink>
199 </li>
200 )
201}
202
203function ListItemWithIcon({
204 title,
205 href,
206 icon,
207 children,
208}: {
209 title: string
210 href: string
211 icon: React.ReactNode
212 children: React.ReactNode
213}) {
214 return (
215 <li>
216 <NavigationMenuLink asChild>
217 <Link
218 href={href}
219 className="hover:bg-secondary/10 flex items-start gap-3 rounded-xl px-2 py-3 transition-colors"
220 >
221 {icon}
222 <div>
223 <div className="text-primary mb-1 text-sm leading-none font-medium">
224 {title}
225 </div>
226 <p className="text-sm leading-snug">{children}</p>
227 </div>
228 </Link>
229 </NavigationMenuLink>
230 </li>
231 )
232}
233Install the following dependencies:
1'use client'
2
3import * as React from 'react'
4import Link from 'next/link'
5
6import {
7 NavigationMenu,
8 NavigationMenuItem,
9 NavigationMenuLink,
10 NavigationMenuList,
11 navigationMenuTriggerStyle,
12} from '@/components/ui/navigation-menu'
13
14export function SimpleTextNavDemo() {
15 return (
16 <NavigationMenu>
17 <NavigationMenuList className="gap-4">
18 <NavigationMenuItem>
19 <NavigationMenuLink
20 asChild
21 className={navigationMenuTriggerStyle()}
22 >
23 <Link
24 href="/"
25 className="underline-offset-2 hover:underline"
26 >
27 Home
28 </Link>
29 </NavigationMenuLink>
30 </NavigationMenuItem>
31 <NavigationMenuItem>
32 <NavigationMenuLink
33 asChild
34 className={navigationMenuTriggerStyle()}
35 >
36 <Link
37 href="/about"
38 className="underline-offset-2 hover:underline"
39 >
40 About Us
41 </Link>
42 </NavigationMenuLink>
43 </NavigationMenuItem>
44 <NavigationMenuItem>
45 <NavigationMenuLink
46 asChild
47 className={navigationMenuTriggerStyle()}
48 >
49 <Link
50 href="/contact"
51 className="underline-offset-2 hover:underline"
52 >
53 Contact
54 </Link>
55 </NavigationMenuLink>
56 </NavigationMenuItem>
57 </NavigationMenuList>
58 </NavigationMenu>
59 )
60}
61The toggle.
| Prop | Type | Default |
|---|---|---|
| defaultValue | string | - |
| value | string | - |
| delayDuration | number | 200 |
| skipDelayDuration | number | 300 |
| direction | ltr, rtl | ltr |
| orientation | vertical, horizontal | vertical |
| Data attribute | Values |
|---|---|
| [data-orientation] | vertical, horizontal |
Signifies a submenu. Use it in place of the root part when nested to create a submenu.
| Prop | Type | Default |
|---|---|---|
| defaultValue | string | - |
| value | string | - |
| onValueChange | function (value: string) => void | - |
| orientation | vertical, horizontal | vertical |
| Data attribute | Values |
|---|---|
| [data-orientation] | vertical, horizontal |
Contains the top level menu items.
| Prop | Type | Default |
|---|---|---|
| asChild | boolean | false |
| Data attribute | Values |
|---|---|
| [data-orientation] | vertical, horizontal |