A list of links that allow users to navigate between pages of a website.
<script lang="ts"> import { NavigationMenu } from "bits-ui"; import { CaretDown } from "$icons/index.js"; 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> <NavigationMenu.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> </NavigationMenu.Link> </li> {/snippet} <NavigationMenu.Root class="relative z-10 flex max-w-max flex-1 items-center justify-center" > <NavigationMenu.List class="group flex flex-1 list-none items-center justify-center space-x-1" > <NavigationMenu.Item> <NavigationMenu.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" /> </NavigationMenu.Trigger> <NavigationMenu.Content class="left-0 top-0 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"> <NavigationMenu.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> </NavigationMenu.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> </NavigationMenu.Content> </NavigationMenu.Item> <NavigationMenu.Item> <NavigationMenu.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" /> </NavigationMenu.Trigger> <NavigationMenu.Content class="left-0 top-0 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> </NavigationMenu.Content> </NavigationMenu.Item> <NavigationMenu.Item> <NavigationMenu.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 </NavigationMenu.Link> </NavigationMenu.Item> <NavigationMenu.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> </NavigationMenu.Indicator> </NavigationMenu.List> <div class="absolute left-0 top-full flex justify-center"> <NavigationMenu.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> </NavigationMenu.Root>
import typography from "@tailwindcss/typography"; import animate from "tailwindcss-animate"; import { fontFamily } from "tailwindcss/defaultTheme"; /** @type {import('tailwindcss').Config} */ export default { darkMode: "class", content: ["./src/**/*.{html,js,svelte,ts}"], theme: { container: { center: true, screens: { "2xl": "1440px", }, }, extend: { colors: { border: { DEFAULT: "hsl(var(--border-card))", input: "hsl(var(--border-input))", "input-hover": "hsl(var(--border-input-hover))", }, background: { DEFAULT: "hsl(var(--background) / <alpha-value>)", alt: "hsl(var(--background-alt) / <alpha-value>)", }, foreground: { DEFAULT: "hsl(var(--foreground) / <alpha-value>)", alt: "hsl(var(--foreground-alt) / <alpha-value>)", }, muted: { DEFAULT: "hsl(var(--muted) / <alpha-value>)", foreground: "hsl(var(--muted-foreground))", }, dark: { DEFAULT: "hsl(var(--dark) / <alpha-value>)", 4: "hsl(var(--dark-04))", 10: "hsl(var(--dark-10))", 40: "hsl(var(--dark-40))", }, accent: { DEFAULT: "hsl(var(--accent) / <alpha-value>)", foreground: "hsl(var(--accent-foreground) / <alpha-value>)", }, destructive: { DEFAULT: "hsl(var(--destructive) / <alpha-value>)", }, contrast: { DEFAULT: "hsl(var(--contrast) / <alpha-value>)", }, }, fontFamily: { sans: ["Inter", ...fontFamily.sans], mono: ["Source Code Pro", ...fontFamily.mono], alt: ["Courier", ...fontFamily.sans], }, fontSize: { xxs: "10px", }, borderWidth: { 6: "6px", }, borderRadius: { card: "16px", "card-lg": "20px", "card-sm": "10px", input: "9px", button: "5px", "5px": "5px", "9px": "9px", "10px": "10px", "15px": "15px", }, height: { input: "3rem", "input-sm": "2.5rem", }, boxShadow: { mini: "var(--shadow-mini)", "mini-inset": "var(--shadow-mini-inset)", popover: "var(--shadow-popover)", kbd: "var(--shadow-kbd)", btn: "var(--shadow-btn)", card: "var(--shadow-card)", "date-field-focus": "var(--shadow-date-field-focus)", }, opacity: { 8: "0.08", }, scale: { 80: ".80", 98: ".98", 99: ".99", }, }, keyframes: { "accordion-down": { from: { height: "0" }, to: { height: "var(--bits-accordion-content-height)" }, }, "accordion-up": { from: { height: "var(--bits-accordion-content-height)" }, to: { height: "0" }, }, "caret-blink": { "0%,70%,100%": { opacity: "1" }, "20%,50%": { opacity: "0" }, }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", "caret-blink": "caret-blink 1.25s ease-out infinite", }, }, plugins: [typography, animate], };
@import url("https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"); @tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { /* Colors */ --background: 0 0% 100%; --background-alt: 0 0% 100%; --foreground: 0 0% 9%; --foreground-alt: 0 0% 32%; --muted: 240 5% 96%; --muted-foreground: 0 0% 9% / 0.4; --border: 240 6% 10%; --border-input: 240 6% 10% / 0.17; --border-input-hover: 240 6% 10% / 0.4; --border-card: 240 6% 10% / 0.1; --dark: 240 6% 10%; --dark-10: 240 6% 10% / 0.1; --dark-40: 240 6% 10% / 0.4; --dark-04: 240 6% 10% / 0.04; --accent: 204 94% 94%; --accent-foreground: 204 80% 16%; --destructive: 347 77% 50%; /* black */ --constrast: 0 0% 0%; /* Shadows */ --shadow-mini: 0px 1px 0px 1px rgba(0, 0, 0, 0.04); --shadow-mini-inset: 0px 1px 0px 0px rgba(0, 0, 0, 0.04) inset; --shadow-popover: 0px 7px 12px 3px hsla(var(--dark-10)); --shadow-kbd: 0px 2px 0px 0px rgba(0, 0, 0, 0.07); --shadow-btn: 0px 1px 0px 1px rgba(0, 0, 0, 0.03); --shadow-card: 0px 2px 0px 1px rgba(0, 0, 0, 0.04); --shadow-date-field-focus: 0px 0px 0px 3px rgba(24, 24, 27, 0.17); } .dark { /* Colors */ --background: 0 0% 5%; --background-alt: 0 0% 8%; --foreground: 0 0% 95%; --foreground-alt: 0 0% 70%; --muted: 240 4% 16%; --muted-foreground: 0 0% 100% / 0.4; --border: 0 0% 96%; --border-input: 0 0% 96% / 0.17; --border-input-hover: 0 0% 96% / 0.4; --border-card: 0 0% 96% / 0.1; --dark: 0 0% 96%; --dark-40: 0 0% 96% / 0.4; --dark-10: 0 0% 96% / 0.1; --dark-04: 0 0% 96% / 0.04; --accent: 204 90 90%; --accent-foreground: 204 94% 94%; --destructive: 350 89% 60%; /* white */ --constrast: 0 0% 100%; /* Shadows */ --shadow-mini: 0px 1px 0px 1px rgba(0, 0, 0, 0.3); --shadow-mini-inset: 0px 1px 0px 0px rgba(0, 0, 0, 0.5) inset; --shadow-popover: 0px 7px 12px 3px hsla(0deg 0% 0% / 30%); --shadow-kbd: 0px 2px 0px 0px rgba(255, 255, 255, 0.07); --shadow-btn: 0px 1px 0px 1px rgba(0, 0, 0, 0.2); --shadow-card: 0px 2px 0px 1px rgba(0, 0, 0, 0.4); --shadow-date-field-focus: 0px 0px 0px 3px rgba(244, 244, 245, 0.1); } } @layer base { * { @apply border-border; } html { -webkit-text-size-adjust: 100%; font-variation-settings: normal; } body { @apply bg-background text-foreground; font-feature-settings: "rlig" 1, "calt" 1; } /* Mobile tap highlight */ /* https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-tap-highlight-color */ html { -webkit-tap-highlight-color: rgba(128, 128, 128, 0.5); } ::selection { background: #fdffa4; color: black; } /* === Scrollbars === */ ::-webkit-scrollbar { @apply w-2; @apply h-2; } ::-webkit-scrollbar-track { @apply !bg-transparent; } ::-webkit-scrollbar-thumb { @apply rounded-card-lg !bg-dark-10; } ::-webkit-scrollbar-corner { background: rgba(0, 0, 0, 0); } /* Firefox */ /* https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color#browser_compatibility */ html { scrollbar-color: var(--bg-muted); } .antialised { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } } @layer utilities { .step { counter-increment: step; } .step:before { @apply absolute inline-flex h-9 w-9 items-center justify-center rounded-full border-4 border-background bg-muted text-center -indent-px font-mono text-base font-medium; @apply ml-[-50px] mt-[-4px]; content: counter(step); } } @layer components { *:not(body):not(.focus-override) { outline: none !important; &:focus-visible { @apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground focus-visible:ring-offset-2 focus-visible:ring-offset-background; } } .link { @apply inline-flex items-center gap-1 rounded-sm font-medium underline underline-offset-4 hover:text-foreground/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground focus-visible:ring-offset-2 focus-visible:ring-offset-background; } input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } /* Firefox */ input[type="number"] { -moz-appearance: textfield; } }
<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>