Navigation Menu

A list of links that allow users to navigate between pages of a website.

	<script lang="ts">
  import { NavMenu } from "bits-ui";
  import CaretDown from "phosphor-svelte/lib/CaretDown";
  import { cn } from "$lib/utils/styles.js";
 
  const components: { title: string; href: string; description: string }[] = [
    {
      title: "Alert Dialog",
      href: "/docs/components/alert-dialog",
      description:
        "A modal dialog that interrupts the user with important content and expects a response."
    },
    {
      title: "Link Preview",
      href: "/docs/components/link-preview",
      description:
        "For sighted users to preview content available behind a link."
    },
    {
      title: "Progress",
      href: "/docs/components/progress",
      description:
        "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar."
    },
    {
      title: "Scroll-area",
      href: "/docs/components/scroll-area",
      description: "Visually or semantically separates content."
    },
    {
      title: "Tabs",
      href: "/docs/components/tabs",
      description:
        "A set of layered sections of content—known as tab panels—that are displayed one at a time."
    },
    {
      title: "Tooltip",
      href: "/docs/components/tooltip",
      description:
        "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it."
    }
  ];
 
  type ListItemProps = {
    className?: string;
    title: string;
    href: string;
    content: string;
  };
</script>
 
{#snippet ListItem({ className, title, content, href }: ListItemProps)}
  <li>
    <NavMenu.Link
      class={cn(
        "block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-muted hover:text-accent-foreground focus:bg-muted focus:text-accent-foreground",
        className
      )}
      {href}
    >
      <div class="text-sm font-medium leading-none">{title}</div>
      <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
        {content}
      </p>
    </NavMenu.Link>
  </li>
{/snippet}
 
<NavMenu.Root
  class="relative z-10 flex max-w-max flex-1 items-center justify-center"
>
  <NavMenu.List
    class="group flex flex-1 list-none items-center justify-center space-x-1"
  >
    <NavMenu.Item>
      <NavMenu.Trigger
        class="group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-muted hover:text-accent-foreground focus:bg-muted focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-muted/50 data-[state=open]:bg-muted/50"
      >
        Getting started
        <CaretDown
          class="group-data[state=open]:rotate-180 relative top-[1px] ml-1 size-3 transition duration-200"
          aria-hidden="true"
        />
      </NavMenu.Trigger>
      <NavMenu.Content
        class="left-0 top-0 z-50 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out 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 md:absolute md:w-auto"
      >
        <ul
          class="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]"
        >
          <li class="row-span-3">
            <NavMenu.Link
              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 focus:shadow-md"
            >
              <!-- <Icons.logo class="h-6 w-6" /> -->
              <div class="mb-2 mt-4 text-lg font-medium">Bits UI</div>
              <p class="text-sm leading-tight text-muted-foreground">
                The headless components for Svelte.
              </p>
            </NavMenu.Link>
          </li>
 
          {@render ListItem({
            href: "/docs",
            title: "Introduction",
            content: "Headless components for Svelte and SvelteKit"
          })}
          {@render ListItem({
            href: "/docs/getting-started",
            title: "Getting Started",
            content: "How to install and use Bits UI"
          })}
          {@render ListItem({
            href: "/docs/styling",
            title: "Styling",
            content: "How to style Bits UI components"
          })}
        </ul>
      </NavMenu.Content>
    </NavMenu.Item>
    <NavMenu.Item>
      <NavMenu.Trigger
        class="group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-muted hover:text-accent-foreground focus:bg-muted focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-muted/50 data-[state=open]:bg-muted/50"
      >
        Components
        <CaretDown
          class="group-data[state=open]:rotate-180 relative top-[1px] ml-1 size-3 transition duration-200"
          aria-hidden="true"
        />
      </NavMenu.Trigger>
      <NavMenu.Content
        class="left-0 top-0 z-50 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out 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 md:absolute md:w-auto"
      >
        <ul
          class="grid w-[400px] gap-3 p-6 md:w-[500px] md:grid-cols-2 lg:w-[600px]"
        >
          {#each components as component (component.title)}
            {@render ListItem({
              href: component.href,
              title: component.title,
              content: component.description
            })}
          {/each}
        </ul>
      </NavMenu.Content>
    </NavMenu.Item>
    <NavMenu.Item>
      <NavMenu.Link
        class="group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-muted hover:text-accent-foreground focus:bg-muted focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-muted/50 data-[state=open]:bg-muted/50"
        href="/docs"
      >
        Documentation
      </NavMenu.Link>
    </NavMenu.Item>
    <NavMenu.Indicator
      class="top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in"
    >
      <div
        class="relative top-[60%] size-2 rotate-45 rounded-tl-sm bg-border shadow-md"
      ></div>
    </NavMenu.Indicator>
  </NavMenu.List>
  <div class="absolute left-0 top-full flex justify-center">
    <NavMenu.Viewport
      class="origin-top-center text-popover-foreground relative mt-1.5 h-[var(--bits-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-background shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--bits-navigation-menu-viewport-width)]"
    />
  </div>
</NavMenu.Root>

Structure

	<script lang="ts">
	import { NavigationMenu } from "bits-ui";
</script>
 
<NavigationMenu.Root>
	<NavigationMenu.List>
		<NavigationMenu.Item>
			<NavigationMenu.Trigger />
			<NavigationMenu.Content />
		</NavigationMenu.Item>
		<NavigationMenu.Item>
			<NavigationMenu.Trigger />
			<NavigationMenu.Content>
				<NavigationMenu.Link />
			</NavigationMenu.Content>
		</NavigationMenu.Item>
		<NavigationMenu.Item>
			<NavigationMenu.Link />
		</NavigationMenu.Item>
		<NavigationMenu.Indicator />
	</NavigationMenu.List>
	<NavigationMenu.Viewport />
</NavigationMenu.Root>

API Reference

NavigationMenu.Root

The root navigation menu component which manages & scopes the state of the navigation menu.

Property Type Description
value $bindable
string

The value of the currently active menu.

Default: undefined
onValueChange
function

A callback function called when the active menu value changes.

Default: undefined
controlledValue
boolean

Whether or not the value is controlled or not. If true, the component will not update the value state internally, instead it will call onValueChange when it would have otherwise, and it is up to you to update the value prop that is passed to the component.

Default: false
dir
enum

The reading direction of the app.

Default: ltr
skipDelayDuration
number

How much time a user has to enter another trigger without incurring a delay again.

Default: 300
delayDuration
number

The duration from when the mouse enters a trigger until the content opens.

Default: 200
orientation
enum

The orientation of the menu.

Default: horizontal
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.List

A menu within the menubar.

Property Type Description
ref $bindable
HTMLUListElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.Item

A list item within the navigation menu.

Property Type Description
value
string

The value of the item.

Default: undefined
ref $bindable
HTMLLiElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.Trigger

The button element which toggles the dropdown menu.

Property Type Description
disabled
boolean

Whether or not the trigger is disabled.

Default: false
ref $bindable
HTMLButtonElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.Content

The content displayed when the dropdown menu is open.

Property Type Description
onInteractOutside
function

Callback fired when an outside interaction event occurs, which is a pointerdown event. You can call event.preventDefault() to prevent the default behavior of handling the outside interaction.

Default: undefined
onFocusOutside
function

Callback fired when focus leaves the dismissible layer. You can call event.preventDefault() to prevent the default behavior on focus leaving the layer.

Default: undefined
interactOutsideBehavior
enum

The behavior to use when an interaction occurs outside of the floating content. 'close' will close the content immediately. 'ignore' will prevent the content from closing. 'defer-otherwise-close' will defer to the parent element if it exists, otherwise it will close the content. 'defer-otherwise-ignore' will defer to the parent element if it exists, otherwise it will ignore the interaction.

Default: close
onEscapeKeydown
function

Callback fired when an escape keydown event occurs in the floating content. You can call event.preventDefault() to prevent the default behavior of handling the escape keydown event.

Default: undefined
escapeKeydownBehavior
enum

The behavior to use when an escape keydown event occurs in the floating content. 'close' will close the content immediately. 'ignore' will prevent the content from closing. 'defer-otherwise-close' will defer to the parent element if it exists, otherwise it will close the content. 'defer-otherwise-ignore' will defer to the parent element if it exists, otherwise it will ignore the interaction.

Default: close
forceMount
boolean

Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.

Default: false
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.Link

A link within the navigation menu.

Property Type Description
active
boolean

Whether or not the link is active.

Default: false
onSelect
function

A callback function called when the link is selected.

Default: undefined
ref $bindable
HTMLAnchorElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.Viewport

The viewport element for the navigation menu, which is used to contain the menu items.

Property Type Description
forceMount
boolean

Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.

Default: false
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined

NavigationMenu.Indicator

The indicator element for the navigation menu, which is used to indicate the current active item.

Property Type Description
forceMount
boolean

Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.

Default: false
ref $bindable
HTMLSpanElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined