Organizes and presents a collection of menu options or actions within a horizontal bar.
<script lang="ts"> import { Menubar } from "bits-ui"; import { CaretRight, Cat, Check, SwitchOff, SwitchOn } from "$icons/index.js"; let selectedView = $state("table"); let selectedProfile = $state("pavel"); let grids = $state([ { checked: true, label: "Pixel" }, { checked: false, label: "Layout" } ]); let showConfigs = $state([ { checked: true, label: "Show Bookmarks" }, { checked: false, label: "Show Full URLs" } ]); const profiles = [ { value: "hunter", label: "Hunter" }, { value: "pavel", label: "Pavel" }, { value: "adrian", label: "Adrian" } ]; const views = [ { value: "table", label: "Table" }, { value: "board", label: "Board" }, { value: "gallery", label: "Gallery" } ]; </script> <Menubar.Root class="flex h-12 items-center gap-1 rounded-10px border border-dark-10 bg-background-alt px-[3px] shadow-mini" > <div class="px-2.5"> <Cat class="size-6" /> </div> <Menubar.Menu> <Menubar.Trigger class="inline-flex h-10 cursor-default items-center justify-center rounded-9px px-3 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted data-[state=open]:bg-muted" > View </Menubar.Trigger> <Menubar.Content class="focus-override z-50 w-full max-w-[220px] rounded-xl border border-muted bg-background px-1 py-1.5 shadow-popover focus-visible:outline-none" align="start" sideOffset={3} > {#each grids as grid} <Menubar.CheckboxItem class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" bind:checked={grid.checked} > {#snippet children({ checked })} {grid.label} grid {#if checked} <SwitchOn /> {:else} <div class="ml-auto"> <SwitchOff /> </div> {/if} {/snippet} </Menubar.CheckboxItem> {/each} <Menubar.Separator class="my-1 -ml-1 -mr-1 block h-px bg-muted" /> <Menubar.RadioGroup bind:value={selectedView}> {#each views as view} <Menubar.RadioItem value={view.value} class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" > {#snippet children({ checked })} {view.label} {#if checked} <Check class="size-5" /> {/if} {/snippet} </Menubar.RadioItem> {/each} </Menubar.RadioGroup> </Menubar.Content> </Menubar.Menu> <Menubar.Menu> <Menubar.Trigger class="inline-flex h-10 cursor-default items-center justify-center rounded-[9px] px-3 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted data-[state=open]:bg-muted" >Edit</Menubar.Trigger > <Menubar.Content class="focus-override z-50 w-full max-w-[220px] rounded-xl border border-muted bg-background px-1 py-1.5 shadow-popover focus-visible:outline-none" align="start" sideOffset={3} > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Undo</Menubar.Item > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Redo</Menubar.Item > <Menubar.Separator /> <Menubar.Sub> <Menubar.SubTrigger class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted data-[state=open]:bg-muted" > Find <div class="ml-auto flex items-center gap-px"> <CaretRight class="h-4 w-4 text-foreground-alt" /> </div> </Menubar.SubTrigger> <Menubar.SubContent class="focus-override w-full max-w-[209px] rounded-xl border border-muted bg-background px-1 py-1.5 shadow-popover focus-visible:outline-none" > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Search the web</Menubar.Item > <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Find...</Menubar.Item > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Find Next</Menubar.Item > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Find Previous</Menubar.Item > </Menubar.SubContent> </Menubar.Sub> <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Cut</Menubar.Item > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Copy</Menubar.Item > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Paste</Menubar.Item > </Menubar.Content> </Menubar.Menu> <Menubar.Menu> <Menubar.Trigger class="inline-flex h-10 cursor-default items-center justify-center rounded-9px px-3 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted data-[state=open]:bg-muted" >View</Menubar.Trigger > <Menubar.Content class="focus-override z-50 w-full max-w-[220px] rounded-xl border border-muted bg-background px-1 py-1.5 shadow-popover focus-visible:outline-none" align="start" sideOffset={3} > {#each showConfigs as config} <Menubar.CheckboxItem class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" bind:checked={config.checked} > {#snippet children({ checked })} {config.label} {#if checked} <SwitchOn /> {:else} <div class="ml-auto"> <SwitchOff /> </div> {/if} {/snippet} </Menubar.CheckboxItem> {/each} <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Reload</Menubar.Item > <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Force Reload</Menubar.Item > <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Toggle Fullscreen</Menubar.Item > <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Hide Sidebar</Menubar.Item > </Menubar.Content> </Menubar.Menu> <Menubar.Menu> <Menubar.Trigger class="mr-[20px] inline-flex h-10 cursor-default items-center justify-center rounded-[9px] px-3 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted data-[state=open]:bg-muted" >Profiles</Menubar.Trigger > <Menubar.Content class="focus-override z-50 w-full max-w-[220px] rounded-xl border border-muted bg-background px-1 py-1.5 shadow-popover focus-visible:outline-none" align="start" sideOffset={3} > <Menubar.RadioGroup bind:value={selectedProfile}> {#each profiles as profile} <Menubar.RadioItem class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" value={profile.value} > {#snippet children({ checked })} {profile.label} {#if checked} <Check class="size-5" /> {/if} {/snippet} </Menubar.RadioItem> {/each} </Menubar.RadioGroup> <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Edit...</Menubar.Item > <Menubar.Separator /> <Menubar.Item class="flex h-10 select-none items-center rounded-button py-3 pl-3 pr-1.5 text-sm font-medium !ring-0 !ring-transparent data-[highlighted]:bg-muted" >Add Profile...</Menubar.Item > </Menubar.Content> </Menubar.Menu> </Menubar.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 { Menubar } from "bits-ui"; </script> <Menubar.Root> <Menubar.Menu> <Menubar.Trigger /> <Menubar.Content> <Menubar.Label /> <Menubar.Item /> <Menubar.Group> <Menubar.Item /> </Menubar.Group> <Menubar.CheckboxItem> <Menubar.CheckboxIndicator /> </Menubar.CheckboxItem> <Menubar.RadioGroup> <Menubar.RadioItem> <Menubar.RadioIndicator /> <Menubar.RadioItem> </Menubar.RadioGroup> <Menubar.Sub> <Menubar.SubTrigger /> <Menubar.SubContent /> </Menubar.Sub> <Menubar.Separator /> <Menubar.Arrow /> </Menubar.Content> </Menubar.Menu> </Menubar.Root>