A collection of links for navigating websites.
import { siteConfig } from "@/config/site"; import { NavigationMenu, NavigationMenuContent, NavigationMenuDescription, NavigationMenuItem, NavigationMenuItemLabel, NavigationMenuLink, NavigationMenuTrigger, } from "@repo/tailwindcss/ui/navigation-menu"; import type { ParentProps } from "solid-js"; import { For } from "solid-js"; const ListItem = (props: ParentProps<{ title: string; href: string }>) => { return ( <NavigationMenuLink href={props.href} class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-[box-shadow,background-color] duration-200 hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring" > <NavigationMenuItemLabel class="text-sm font-medium leading-none"> {props.title} </NavigationMenuItemLabel> <NavigationMenuDescription class="line-clamp-2 text-sm leading-snug text-muted-foreground"> {props.children} </NavigationMenuDescription> </NavigationMenuLink> ); }; const components: { title: string; href: string; description: string }[] = [ { title: "Data Table", href: "/docs/components/data-table", description: "Powerful table and datagrids built using TanStack Table.", }, { title: "Date Picker", href: "/docs/components/date-picker", description: "A component that allows users to select a date from a calendar.", }, { title: "OTP Field", href: "/docs/components/otp-field", description: "An accessible and customizable OTP Input component.", }, { title: "Resizable", href: "/docs/components/resizable", description: "A component that divides your interface into resizable sections.", }, { title: "Sonner", href: "/docs/components/sonner", description: "An opinionated toast component for Solid.", }, { title: "Toggle Group", href: "/docs/components/toggle-group", description: "A set of two-state buttons that can be toggled on (pressed) or off (not pressed).", }, ]; const NavigationMenuDemo = () => { return ( <NavigationMenu> <NavigationMenuItem> <NavigationMenuTrigger class="transition-[box-shadow,background-color] focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring data-[expanded]:bg-accent"> Learn </NavigationMenuTrigger> <NavigationMenuContent class="grid gap-3 p-4 w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] [&>li:first-of-type]:row-span-3"> <NavigationMenuLink href="/" class="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none transition-shadow duration-200 hover:shadow-md focus-visible:shadow-md focus-visible:ring-[1.5px] focus-visible:ring-ring" > <NavigationMenuItemLabel class="mb-2 mt-4 text-lg font-medium"> {siteConfig.title} </NavigationMenuItemLabel> <NavigationMenuDescription class="text-sm leading-tight text-muted-foreground"> {siteConfig.description} </NavigationMenuDescription> </NavigationMenuLink> <ListItem href="/docs" title="Introduction"> {siteConfig.description}. </ListItem> <ListItem href="/docs/installation" title="Installation"> How to install dependencies and structure your app. </ListItem> <ListItem href="/docs/components/typography" title="Typography"> Styles for headings, paragraphs, lists...etc. </ListItem> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger class="transition-[box-shadow,background-color] focus-visible:outline-none focus-visible:ring-1.5px focus-visible:ring-ring data-[expanded]:bg-accent"> Overview </NavigationMenuTrigger> <NavigationMenuContent class="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]"> <For each={components}> {(item) => ( <ListItem href={item.href} title={item.title}> {item.description} </ListItem> )} </For> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuTrigger as="a" href="/docs" class="transition-[box-shadow,background-color] focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring data-[expanded]:bg-accent" > Documentation </NavigationMenuTrigger> </NavigationMenu> ); }; export default NavigationMenuDemo;
npx shadcn-solid@latest add navigation-menu
npm install @kobalte/core
import { cn } from "@/libs/cn"; import type { NavigationMenuContentProps, NavigationMenuRootProps, NavigationMenuTriggerProps, } from "@kobalte/core/navigation-menu"; import { NavigationMenu as NavigationMenuPrimitive } from "@kobalte/core/navigation-menu"; import type { PolymorphicProps } from "@kobalte/core/polymorphic"; import { type ParentProps, Show, type ValidComponent, mergeProps, splitProps, } from "solid-js"; export const NavigationMenuItem = NavigationMenuPrimitive.Menu; export const NavigationMenuLink = NavigationMenuPrimitive.Item; export const NavigationMenuItemLabel = NavigationMenuPrimitive.ItemLabel; export const NavigationMenuDescription = NavigationMenuPrimitive.ItemDescription; export const NavigationMenuItemIndicator = NavigationMenuPrimitive.ItemIndicator; export const NavigationMenuSub = NavigationMenuPrimitive.Sub; export const NavigationMenuSubTrigger = NavigationMenuPrimitive.SubTrigger; export const NavigationMenuSubContent = NavigationMenuPrimitive.SubContent; export const NavigationMenuRadioGroup = NavigationMenuPrimitive.RadioGroup; export const NavigationMenuRadioItem = NavigationMenuPrimitive.RadioItem; export const NavigationMenuCheckboxItem = NavigationMenuPrimitive.CheckboxItem; export const NavigationMenuSeparator = NavigationMenuPrimitive.Separator; type withArrow = { withArrow?: boolean; }; type navigationMenuProps<T extends ValidComponent = "ul"> = ParentProps< NavigationMenuRootProps<T> & withArrow & { class?: string; } >; export const NavigationMenu = <T extends ValidComponent = "ul">( props: PolymorphicProps<T, navigationMenuProps<T>>, ) => { const merge = mergeProps<navigationMenuProps<T>[]>( { get gutter() { return props.withArrow ? props.gutter : 6; }, withArrow: false, flip: false, }, props, ); const [local, rest] = splitProps(merge as navigationMenuProps, [ "class", "children", "withArrow", ]); return ( <NavigationMenuPrimitive class={cn("flex w-max items-center justify-center gap-x-1", local.class)} {...rest} > {local.children} <NavigationMenuPrimitive.Viewport class={cn( "pointer-events-none z-50 overflow-x-clip overflow-y-visible rounded-md border bg-popover text-popover-foreground shadow", "h-[--kb-navigation-menu-viewport-height] w-[--kb-navigation-menu-viewport-width] transition-[width,height] duration-300", "origin-[--kb-menu-content-transform-origin]", "data-[expanded]:duration-300 data-[expanded]:animate-in data-[expanded]:fade-in data-[expanded]:zoom-in-95", "data-[closed]:duration-300 data-[closed]:animate-out data-[closed]:fade-out data-[closed]:zoom-out-95", )} > <Show when={local.withArrow}> <NavigationMenuPrimitive.Arrow class="transition-transform duration-300" /> </Show> </NavigationMenuPrimitive.Viewport> </NavigationMenuPrimitive> ); }; type navigationMenuTriggerProps<T extends ValidComponent = "button"> = ParentProps< NavigationMenuTriggerProps<T> & withArrow & { class?: string; } >; export const NavigationMenuTrigger = <T extends ValidComponent = "button">( props: PolymorphicProps<T, navigationMenuTriggerProps<T>>, ) => { const merge = mergeProps<navigationMenuTriggerProps<T>[]>( { get withArrow() { return props.as === undefined ? true : props.withArrow; }, }, props, ); const [local, rest] = splitProps(merge as navigationMenuTriggerProps, [ "class", "children", "withArrow", ]); return ( <NavigationMenuPrimitive.Trigger class={cn( "inline-flex w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium outline-none transition-colors duration-300 hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", local.class, )} {...rest} > {local.children} <Show when={local.withArrow}> <NavigationMenuPrimitive.Icon class="ml-1 size-3 transition-transform duration-300 data-[expanded]:rotate-180" as="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" > <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m6 9l6 6l6-6" /> </NavigationMenuPrimitive.Icon> </Show> </NavigationMenuPrimitive.Trigger> ); }; type navigationMenuContentProps<T extends ValidComponent = "ul"> = ParentProps< NavigationMenuContentProps<T> & { class?: string; } >; export const NavigationMenuContent = <T extends ValidComponent = "ul">( props: PolymorphicProps<T, navigationMenuContentProps<T>>, ) => { const [local, rest] = splitProps(props as navigationMenuContentProps, [ "class", "children", ]); return ( <NavigationMenuPrimitive.Portal> <NavigationMenuPrimitive.Content class={cn( "absolute left-0 top-0 p-4 outline-none", "data-[motion^=from-]:duration-300 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52", "data-[motion^=to-]:duration-300 data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52", local.class, )} {...rest} > {local.children} </NavigationMenuPrimitive.Content> </NavigationMenuPrimitive.Portal> ); };
import { cn } from "@/libs/cn"; import type { NavigationMenuContentProps, NavigationMenuRootProps, NavigationMenuTriggerProps, } from "@kobalte/core/navigation-menu"; import { NavigationMenu as NavigationMenuPrimitive } from "@kobalte/core/navigation-menu"; import type { PolymorphicProps } from "@kobalte/core/polymorphic"; import { type ParentProps, Show, type ValidComponent, mergeProps, splitProps, } from "solid-js"; export const NavigationMenuItem = NavigationMenuPrimitive.Menu; export const NavigationMenuLink = NavigationMenuPrimitive.Item; export const NavigationMenuItemLabel = NavigationMenuPrimitive.ItemLabel; export const NavigationMenuDescription = NavigationMenuPrimitive.ItemDescription; export const NavigationMenuItemIndicator = NavigationMenuPrimitive.ItemIndicator; export const NavigationMenuSub = NavigationMenuPrimitive.Sub; export const NavigationMenuSubTrigger = NavigationMenuPrimitive.SubTrigger; export const NavigationMenuSubContent = NavigationMenuPrimitive.SubContent; export const NavigationMenuRadioGroup = NavigationMenuPrimitive.RadioGroup; export const NavigationMenuRadioItem = NavigationMenuPrimitive.RadioItem; export const NavigationMenuCheckboxItem = NavigationMenuPrimitive.CheckboxItem; export const NavigationMenuSeparator = NavigationMenuPrimitive.Separator; type withArrow = { withArrow?: boolean; }; type navigationMenuProps<T extends ValidComponent = "ul"> = ParentProps< NavigationMenuRootProps<T> & withArrow & { class?: string; } >; export const NavigationMenu = <T extends ValidComponent = "ul">( props: PolymorphicProps<T, navigationMenuProps<T>>, ) => { const merge = mergeProps<navigationMenuProps<T>[]>( { get gutter() { return props.withArrow ? props.gutter : 6; }, withArrow: false, flip: false, }, props, ); const [local, rest] = splitProps(merge as navigationMenuProps, [ "class", "children", "withArrow", ]); return ( <NavigationMenuPrimitive class={cn("flex w-max items-center justify-center gap-x-1", local.class)} {...rest} > {local.children} <NavigationMenuPrimitive.Viewport class={cn( "pointer-events-none z-50 overflow-x-clip overflow-y-visible rounded-md border bg-popover text-popover-foreground shadow", "h-[--kb-navigation-menu-viewport-height] w-[--kb-navigation-menu-viewport-width] transition-[width,height] duration-300", "origin-[--kb-menu-content-transform-origin]", "data-[expanded]:(animate-duration-300 animate-in fade-in zoom-in-95)", "data-[closed]:(animate-duration-300 animate-out fade-out zoom-out-95)", )} > <Show when={local.withArrow}> <NavigationMenuPrimitive.Arrow class="transition-transform duration-300" /> </Show> </NavigationMenuPrimitive.Viewport> </NavigationMenuPrimitive> ); }; type navigationMenuTriggerProps<T extends ValidComponent = "button"> = ParentProps< NavigationMenuTriggerProps<T> & withArrow & { class?: string; } >; export const NavigationMenuTrigger = <T extends ValidComponent = "button">( props: PolymorphicProps<T, navigationMenuTriggerProps<T>>, ) => { const merge = mergeProps<navigationMenuTriggerProps<T>[]>( { get withArrow() { return props.as === undefined ? true : props.withArrow; }, }, props, ); const [local, rest] = splitProps(merge as navigationMenuTriggerProps, [ "class", "children", "withArrow", ]); return ( <NavigationMenuPrimitive.Trigger class={cn( "inline-flex w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium outline-none transition-colors duration-300 hover:(bg-accent text-accent-foreground) disabled:(pointer-events-none opacity-50)", local.class, )} {...rest} > {local.children} <Show when={local.withArrow}> <NavigationMenuPrimitive.Icon class="ml-1 size-3 transition-transform duration-300 data-[expanded]:rotate-180" as="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" > <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m6 9l6 6l6-6" /> </NavigationMenuPrimitive.Icon> </Show> </NavigationMenuPrimitive.Trigger> ); }; type navigationMenuContentProps<T extends ValidComponent = "ul"> = ParentProps< NavigationMenuContentProps<T> & { class?: string; } >; export const NavigationMenuContent = <T extends ValidComponent = "ul">( props: PolymorphicProps<T, navigationMenuContentProps<T>>, ) => { const [local, rest] = splitProps(props as navigationMenuContentProps, [ "class", "children", ]); return ( <NavigationMenuPrimitive.Portal> <NavigationMenuPrimitive.Content class={cn( "absolute left-0 top-0 p-4 outline-none", "data-[motion^=from-]:(animate-duration-300 animate-in fade-in) data-[motion=from-end]:slide-in-r-52 data-[motion=from-start]:slide-in-l-52", "data-[motion^=to-]:(animate-duration-300 animate-out fade-out) data-[motion=to-end]:slide-out-r-52 data-[motion=to-start]:slide-out-l-52", local.class, )} {...rest} > {local.children} </NavigationMenuPrimitive.Content> </NavigationMenuPrimitive.Portal> ); };
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuTrigger, } from "@/components/ui/navigation-menu"
<NavigationMenu> <NavigationMenuItem> <NavigationMenuTrigger>Item One</NavigationMenuTrigger> <NavigationMenuContent> <NavigationMenuLink>Link</NavigationMenuLink> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenu>