Menu de navegação
Uma barra horizontal com links e painĂ©is suspensos para cabeçalhos de sites, navegaçÔes em documentos e estruturas de aplicativos â com bordas neobrutalistas e sombras marcantes.
"use client"
import * as React from "react"O navigation menu Ă© uma barra horizontal de links em que qualquer item pode abrir um painel dropdown com mais links. ConstruĂdo sobre o componente Base UI Navigation Menu e estilizado seguindo a receita neobrutalista: bordas grossas, sombras duras e tipografia em negrito.
Quando usar:
- Cabeçalhos de site â links de primeiro nĂvel mais painĂ©is ricos para produtos, seçÔes de docs ou recursos.
- NavegaçÔes de marketing â barras âFuncionalidades / Preços / Recursosâ em que um painel de cartĂ”es funciona melhor do que um paredĂŁo de links.
- Navegação mista â combine itens
NavigationMenuLinksimples com grupos dropdown na mesma barra.
Instalação#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/navigation-menu.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/navigation-menu.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/navigation-menu.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/navigation-menu.json
Instale as seguintes dependĂȘncias:
pnpm add @base-ui/reactnpm install @base-ui/reactyarn add @base-ui/reactbun add @base-ui/react
Copie e cole o cĂłdigo a seguir no seu projeto.
import * as React from "react"
import { cva } from "class-variance-authority"
import { ChevronDownIcon } from "lucide-react"
import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
function NavigationMenu({
className,
children,
viewport = true,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
viewport?: boolean
}) {
return (
<NavigationMenuPrimitive.Root
data-slot="navigation-menu"
data-viewport={viewport}
className={cn(
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
className
)}
{...props}
>
{children}
{viewport && <NavigationMenuViewport />}
</NavigationMenuPrimitive.Root>
)
}
function NavigationMenuList({
className,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
return (
<NavigationMenuPrimitive.List
data-slot="navigation-menu-list"
className={cn(
"group flex flex-1 list-none items-center justify-center gap-0",
className
)}
{...props}
/>
)
}
function NavigationMenuItem({
className,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
return (
<NavigationMenuPrimitive.Item
data-slot="navigation-menu-item"
className={cn("relative", className)}
{...props}
/>
)
}
const navigationMenuTriggerStyle = cva(
"group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground"
)
function NavigationMenuTrigger({
className,
children,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
return (
<NavigationMenuPrimitive.Trigger
data-slot="navigation-menu-trigger"
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
<ChevronDownIcon
className="relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180"
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
)
}
function NavigationMenuContent({
className,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
return (
<NavigationMenuPrimitive.Content
data-slot="navigation-menu-content"
className={cn(
"top-0 left-0 w-full p-1 ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded group-data-[viewport=false]/navigation-menu:border-2 group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow-md group-data-[viewport=false]/navigation-menu:duration-300 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none md:absolute md:w-auto group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",
className
)}
{...props}
/>
)
}
function NavigationMenuViewport({
className,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
return (
<div
className={cn(
"absolute top-full left-0 isolate z-50 flex justify-center"
)}
>
<NavigationMenuPrimitive.Viewport
data-slot="navigation-menu-viewport"
className={cn(
"origin-top-center relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded border-2 bg-popover text-popover-foreground shadow-md duration-100 md:w-(--radix-navigation-menu-viewport-width) data-open:animate-in data-open:zoom-in-90 data-closed:animate-out data-closed:zoom-out-90",
className
)}
{...props}
/>
</div>
)
}
function NavigationMenuLink({
className,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
return (
<NavigationMenuPrimitive.Link
data-slot="navigation-menu-link"
className={cn(
"flex items-center gap-2 rounded-sm p-2 text-sm transition-all outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary in-data-[slot=navigation-menu-content]:rounded-sm data-active:bg-accent data-active:text-accent-foreground [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
/>
)
}
function NavigationMenuIndicator({
className,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
return (
<NavigationMenuPrimitive.Indicator
data-slot="navigation-menu-indicator"
className={cn(
"top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in",
className
)}
{...props}
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
)
}
export {
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
navigationMenuTriggerStyle,
}
Atualize os caminhos de importação conforme a configuração do seu projeto.
Uso#
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink>Link</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>Composição#
Use a seguinte composição para construir um NavigationMenu:
NavigationMenu
âââ NavigationMenuList
â âââ NavigationMenuItem
â â âââ NavigationMenuTrigger
â â âââ NavigationMenuContent
â â âââ NavigationMenuLink
â â âââ NavigationMenuLink
â âââ NavigationMenuItem
â âââ NavigationMenuLink
âââ NavigationMenuIndicatorComponente de link#
Use a prop render para compor um componente de link personalizado, como o Link do Next.js.
import Link from "next/link"
import {
NavigationMenuItem,
NavigationMenuLink,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu"
export function NavigationMenuDemo() {
return (
<NavigationMenuItem>
<NavigationMenuLink
render={<Link href="/docs" />}
className={navigationMenuTriggerStyle()}
>
Documentation
</NavigationMenuLink>
</NavigationMenuItem>
)
}RTL#
Para ativar o suporte a RTL no Neobrutalism, consulte o guia de configuração de RTL.
"use client"
import * as React from "react"Acessibilidade#
Apesar do nome, isto nĂŁo Ă© um menu ARIA â roles de menu servem para comandos de aplicação, nĂŁo para navegação entre pĂĄginas. O componente renderiza um landmark nav com links comuns, seguindo o padrĂŁo WAI-ARIA Disclosure Navigation: cada gatilho Ă© um botĂŁo com aria-expanded e aria-controls apontando para o painel que ele abre.
InteraçÔes de teclado (orientação horizontal, o padrão):
| Tecla | Ação |
|---|---|
Tab / Shift + Tab | Move o foco por gatilhos, links e o conteĂșdo do painel aberto |
Space / Enter | Abre o painel do gatilho focado; ativa um link focado |
ArrowRight / ArrowLeft | Move o foco para o gatilho ou link seguinte / anterior |
ArrowDown | Move o foco de um gatilho aberto para dentro do seu painel |
Home / End | Vai para o primeiro / Ășltimo gatilho ou link |
Esc | Fecha o painel aberto e devolve o foco ao seu gatilho |
ReferĂȘncia da API#
Consulte a documentação Base UI Navigation Menu para obter mais informaçÔes.