Header — Mega Menu
blockmarketingNavbar whose product and resources items open a full-width mega panel of grouped, described links plus a highlighted feature card, keyboard navigable and closing on Escape.
Installation
$pnpm dlx uipkge-ng@latest add header-mega-menu$npx uipkge-ng@latest add header-mega-menu$yarn dlx uipkge-ng@latest add header-mega-menu$bunx uipkge-ng@latest add header-mega-menuManifest:
https://uipkge.dev/r/angular/header-mega-menu.jsonInstalls to:src/app/components/blocks/header-mega-menu/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
MegaMenuLinkinterface MegaMenuLink {
icon: LucideIconData
title: string
body: string
}MegaMenuGroupinterface MegaMenuGroup {
heading: string
items: MegaMenuLink[]
}MegaMenuHighlightinterface MegaMenuHighlight {
title: string
body: string
cta: string
}MegaMenuinterface MegaMenu {
label: string
groups: MegaMenuGroup[]
highlight: MegaMenuHighlight
}MegaMenuPlainLinkinterface MegaMenuPlainLink {
label: string
href: string
}npm dependencies
Files installed (2)
src/app/components/blocks/header-mega-menu/header-mega-menu.component.ts10.5 kB
// Navbar whose product and resources items open a full-width mega panel of grouped, // described links plus a highlighted feature card — keyboard navigable, closing on // Escape. Port of the Vue/React block 1:1: panel columns derive from the `menus` // array, so a new group needs no extra markup. import { ChangeDetectionStrategy, Component, Input, signal } from '@angular/core' import { ArrowRight, BarChart3, BookOpen, Boxes, Layers, LifeBuoy, Lock, LucideAngularModule, Menu, Workflow, type LucideIconData, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiButtonComponent } from '@/ui/button/button.component' import { UiNavigationMenuComponent, UiNavigationMenuContentComponent, UiNavigationMenuItemComponent, UiNavigationMenuListComponent, UiNavigationMenuTriggerComponent, navigationMenuTriggerStyle, } from '@/ui/navigation-menu/navigation-menu.component' import { UiSeparatorComponent } from '@/ui/separator/separator.component' import { UiSheetCloseComponent, UiSheetComponent, UiSheetContentComponent, UiSheetHeaderComponent, UiSheetTitleComponent, } from '@/ui/sheet/sheet.component' export interface MegaMenuLink { icon: LucideIconData title: string body: string } export interface MegaMenuGroup { heading: string items: MegaMenuLink[] } export interface MegaMenuHighlight { title: string body: string cta: string } export interface MegaMenu { label: string groups: MegaMenuGroup[] highlight: MegaMenuHighlight } export interface MegaMenuPlainLink { label: string href: string } const menus: MegaMenu[] = [ { label: 'Product', groups: [ { heading: 'Core', items: [ { icon: Boxes, title: 'Metric layer', body: 'Versioned definitions your whole org shares.' }, { icon: BarChart3, title: 'Dashboards', body: 'Composed from certified metrics, not raw SQL.' }, { icon: Workflow, title: 'Pipelines', body: 'Scheduled materialisation with cost ceilings.' }, ], }, { heading: 'Governance', items: [ { icon: Lock, title: 'Row-level access', body: 'Scope evaluated per query, per identity.' }, { icon: BookOpen, title: 'Change history', body: 'Every definition edit reviewed and revertible.' }, { icon: LifeBuoy, title: 'Audit exports', body: 'Generated from the same history, not by hand.' }, ], }, ], highlight: { title: 'Ship your first dashboard today', body: 'Connect a warehouse, publish one certified metric, and invite the team. No migration required.', cta: 'Start the walkthrough', }, }, { label: 'Resources', groups: [ { heading: 'Learn', items: [ { icon: BookOpen, title: 'Documentation', body: 'Setup, modelling, and the access model.' }, { icon: Layers, title: 'Guides', body: 'Reconciliation and first-close checklists.' }, { icon: BarChart3, title: 'Benchmarks', body: 'Close speed across 240 finance teams.' }, ], }, { heading: 'Support', items: [ { icon: LifeBuoy, title: 'Help centre', body: 'Answers to the questions support gets most.' }, { icon: Workflow, title: 'Status', body: 'Live uptime and incident history.' }, { icon: Lock, title: 'Trust centre', body: 'SOC 2, subprocessors, and data residency.' }, ], }, ], highlight: { title: 'Read the rollout plan', body: 'The five-week implementation we run for every customer, written down so you can run it yourself.', cta: 'Open the plan', }, }, ] const plainLinks: MegaMenuPlainLink[] = [ { label: 'Pricing', href: '#pricing' }, { label: 'Customers', href: '#customers' }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-header-mega-menu, [ui-header-mega-menu]', standalone: true, // The block renders its own <header>: keep this wrapper out of the layout. host: { '[attr.class]': '"contents"' }, imports: [ LucideAngularModule, UiButtonComponent, UiNavigationMenuComponent, UiNavigationMenuContentComponent, UiNavigationMenuItemComponent, UiNavigationMenuListComponent, UiNavigationMenuTriggerComponent, UiSeparatorComponent, UiSheetCloseComponent, UiSheetComponent, UiSheetContentComponent, UiSheetHeaderComponent, UiSheetTitleComponent, ], template: ` <header data-slot="header-mega-menu" [class]="rootClass"> <div class="mx-auto flex h-16 max-w-6xl items-center gap-6 px-6"> <a href="#top" class="flex shrink-0 items-center gap-2 font-semibold tracking-tight"> <lucide-icon [img]="Layers" class="text-primary size-5" /> Northwind </a> <nav ui-navigation-menu class="hidden lg:flex"> <ui-navigation-menu-list> @for (menu of megaMenus; track menu.label) { <li ui-navigation-menu-item [value]="menu.label"> <button ui-navigation-menu-trigger>{{ menu.label }}</button> <ui-navigation-menu-content> <div class="grid w-[46rem] grid-cols-[1fr_1fr_16rem] gap-6 p-6"> @for (group of menu.groups; track group.heading) { <div> <p class="text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase"> {{ group.heading }} </p> <ul class="mt-3 space-y-1"> @for (item of group.items; track item.title) { <li> <a href="#" class="hover:bg-muted focus-visible:ring-ring flex gap-3 rounded-md p-2 transition-colors focus-visible:ring-2 focus-visible:outline-none" > <lucide-icon [img]="item.icon" class="text-muted-foreground mt-0.5 size-4 shrink-0" /> <span class="min-w-0"> <span class="block text-sm font-medium">{{ item.title }}</span> <span class="text-muted-foreground block text-xs leading-snug">{{ item.body }}</span> </span> </a> </li> } </ul> </div> } <!-- Highlight rail: one promoted destination per panel, on the muted surface so it reads as an aside, not a sixth link. --> <div class="bg-muted/50 flex flex-col rounded-lg p-4"> <p class="text-sm font-semibold">{{ menu.highlight.title }}</p> <p class="text-muted-foreground mt-2 text-xs leading-relaxed">{{ menu.highlight.body }}</p> <button ui-button variant="link" class="mt-auto h-auto justify-start p-0 pt-4 text-xs"> {{ menu.highlight.cta }} <lucide-icon [img]="ArrowRight" class="ml-1 size-3" /> </button> </div> </div> </ui-navigation-menu-content> </li> } @for (link of plain; track link.href) { <li ui-navigation-menu-item [value]="link.label"> <a [href]="link.href" [class]="plainLinkClass">{{ link.label }}</a> </li> } </ui-navigation-menu-list> </nav> <div class="ml-auto flex items-center gap-2"> <button ui-button variant="ghost" size="sm" class="hidden sm:inline-flex">Sign in</button> <div ui-separator orientation="vertical" class="hidden h-5 sm:block"></div> <button ui-button size="sm">Book a demo</button> </div> <div ui-sheet [open]="mobileOpen()" (openChange)="mobileOpen.set($event)"> <button ui-button variant="ghost" size="icon" class="ml-auto lg:hidden" aria-label="Open navigation menu" (click)="mobileOpen.set(true)" > <lucide-icon [img]="Menu" class="size-5" /> </button> <div ui-sheet-content side="right" class="w-72 overflow-y-auto"> <div ui-sheet-header> <h2 ui-sheet-title>Menu</h2> </div> <nav class="mt-6 grid gap-5" aria-label="Mobile"> @for (menu of megaMenus; track menu.label) { <div> <p class="text-muted-foreground/70 text-xs font-medium tracking-wide uppercase">{{ menu.label }}</p> <ul class="mt-2 grid gap-1"> @for (group of menu.groups; track group.heading) { @for (item of group.items; track item.title) { <li> <a href="#" class="hover:bg-muted block rounded-md px-3 py-2 text-sm font-medium transition-colors" (click)="mobileOpen.set(false)" > {{ item.title }} </a> </li> } } </ul> </div> } <div ui-separator></div> @for (link of plain; track link.href) { <a [href]="link.href" class="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" (click)="mobileOpen.set(false)" > {{ link.label }} </a> } <div ui-separator></div> <div class="grid gap-2"> <button ui-button variant="outline">Sign in</button> <button ui-button>Book a demo</button> </div> </nav> </div> </div> </div> </header> `, }) export class UiHeaderMegaMenuComponent { protected readonly ArrowRight = ArrowRight protected readonly Layers = Layers protected readonly Menu = Menu protected readonly megaMenus = menus protected readonly plain = plainLinks protected readonly plainLinkClass = navigationMenuTriggerStyle() @Input('class') className?: string readonly mobileOpen = signal(false) get rootClass(): string { return cn('border-border bg-background/90 border-b backdrop-blur', this.className) } }src/app/components/blocks/header-mega-menu/index.ts0.2 kB
export { UiHeaderMegaMenuComponent, type MegaMenu, type MegaMenuGroup, type MegaMenuHighlight, type MegaMenuLink, type MegaMenuPlainLink, } from './header-mega-menu.component'
Raw manifest:https://uipkge.dev/r/angular/header-mega-menu.json