Skip to content
W WRNexusJS
layout component

PublicHeader

Reusable public header component.

@wrnexus/ui 0.2.671 props0 slots1 events

Usage

Components are auto-discovered. Use the component directly in any .wrn view:

<PublicHeader />

Legacy mount name: data-component="PublicHeader".

Props and attributes

PropTypeRequirementDefault
classstringOptional""

Slots

This component does not declare a slot.

Events

  • click

Source contract

Installed source: components/PublicHeader.wrn

component PublicHeader {
    props {
        class: string = ""
        homeHref: string = "/"
        brandName: string = "WRNexusJS"
        brandTagline: string = "Identity Cloud"
        brandAriaLabel: string = "WRNexusJS home"
        brandIcon: string = "icon-[lucide--blocks]"
        pricingLabel: string = "Pricing"
        pricingHref: string = "/pricing"
        statusLabel: string = "All systems operational"
        statusHref: string = "/status"
        signInLabel: string = "Sign in"
        signInHref: string = "/sign-in"
        primaryLabel: string = "Start free"
        primaryHref: string = "/sign-up"
        showStatus: boolean = true
        showThemeToggle: boolean = true
        showSignIn: boolean = true
        showPrimaryAction: boolean = true
        productLabel: string = "Product"
        solutionsLabel: string = "Solutions"
        developersLabel: string = "Developers"
        resourcesLabel: string = "Resources"
    }
    state activeMenu = ""
    state mobileMenuOpen = false
    state headerScrolled = false

    view {
        <header
            data-public-header
            class="relative sticky top-0 z-50 w-full border-b transition-all duration-300 {class}"
            class:border-transparent="!headerScrolled"
            class:bg-transparent="!headerScrolled"
            class:border-slate-200/80="headerScrolled"
            class:bg-white/90="headerScrolled"
            class:shadow-sm="headerScrolled"
            class:backdrop-blur-xl="headerScrolled"
            class:dark:border-white/10="headerScrolled"
            class:dark:bg-slate-950/90="headerScrolled"
        >
        <div
                class="relative z-[60] flex h-18 w-full items-center justify-between gap-6 px-5 sm:px-8 lg:px-10 xl:px-12"
            >
        <!-- Brand -->
        <a
                    href="{homeHref}"
                    aria-label="{brandAriaLabel}"
                    class="group inline-flex shrink-0 items-center gap-3 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950"
                >
        <span
                        class="grid h-10 w-10 place-items-center rounded-xl bg-indigo-600 text-white shadow-lg shadow-indigo-600/20 transition duration-200 group-hover:-translate-y-0.5 group-hover:bg-indigo-500 group-hover:shadow-xl"
                    >
        <span class="{brandIcon} h-5 w-5" aria-hidden="true" >
        </span>
        </span>
        <span class="min-w-0">
        <span class="block text-lg font-bold tracking-tight text-slate-950 dark:text-white">
                            {brandName}
                        </span>
        <span
                            class="block text-[10px] font-semibold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400"
                        >
                            {brandTagline}
                        </span>
        </span>
        </a>
        <!-- Desktop navigation -->
        <nav
                    aria-label="Main navigation"
                    class="hidden items-center gap-1 lg:flex"
                >
        <slot name="navigation">
        <!-- Product -->
        <button
                        type="button"
                        @click="activeMenu = activeMenu === 'product' ? '' : 'product'"
                        aria-haspopup="true"
                        aria-expanded="{activeMenu === 'product'}"
                        class="inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
                        class:bg-indigo-50="activeMenu === 'product'"
                        class:text-indigo-700="activeMenu === 'product'"
                        class:text-slate-700="activeMenu !== 'product'"
                        class:hover:bg-slate-100="activeMenu !== 'product'"
                        class:dark:bg-indigo-500/10="activeMenu === 'product'"
                        class:dark:text-indigo-300="activeMenu === 'product'"
                        class:dark:text-slate-300="activeMenu !== 'product'"
                        class:dark:hover:bg-white/5="activeMenu !== 'product'"
                    >
                        {productLabel}

                        <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'product'" aria-hidden="true" >
        </span>
        </button>
        <!-- Solutions -->
        <button
                        type="button"
                        @click="activeMenu = activeMenu === 'solutions' ? '' : 'solutions'"
                        aria-haspopup="true"
                        aria-expanded="{activeMenu === 'solutions'}"
                        class="group inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
                        class:bg-indigo-50="activeMenu === 'solutions'"
                        class:text-indigo-700="activeMenu === 'solutions'"
                        class:text-slate-700="activeMenu !== 'solutions'"
                        class:hover:bg-slate-100="activeMenu !== 'solutions'"
                        class:hover:text-slate-950="activeMenu !== 'solutions'"
                        class:dark:bg-indigo-500/10="activeMenu === 'solutions'"
                        class:dark:text-indigo-300="activeMenu === 'solutions'"
                        class:dark:text-slate-300="activeMenu !== 'solutions'"
                        class:dark:hover:bg-white/5="activeMenu !== 'solutions'"
                        class:dark:hover:text-white="activeMenu !== 'solutions'"
                    >
                        {solutionsLabel}

                        <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'solutions'" aria-hidden="true" >
        </span>
        </button>
        <!-- Developers -->
        <button
                        type="button"
                        @click="activeMenu = activeMenu === 'developers' ? '' : 'developers'"
                        aria-haspopup="true"
                        aria-expanded="{activeMenu === 'developers'}"
                        class="group inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
                        class:bg-indigo-50="activeMenu === 'developers'"
                        class:text-indigo-700="activeMenu === 'developers'"
                        class:text-slate-700="activeMenu !== 'developers'"
                        class:hover:bg-slate-100="activeMenu !== 'developers'"
                        class:hover:text-slate-950="activeMenu !== 'developers'"
                        class:dark:bg-indigo-500/10="activeMenu === 'developers'"
                        class:dark:text-indigo-300="activeMenu === 'developers'"
                        class:dark:text-slate-300="activeMenu !== 'developers'"
                        class:dark:hover:bg-white/5="activeMenu !== 'developers'"
                        class:dark:hover:text-white="activeMenu !== 'developers'"
                    >
                        {developersLabel}

                        <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'developers'"  aria-hidden="true" >
        </span>
        </button>
        <!-- Resources -->
        <button
                        type="button"
                        @click="activeMenu = activeMenu === 'resources' ? '' : 'resources'"
                        aria-haspopup="true"
                        aria-expanded="{activeMenu === 'resources'}"
                        class="group inline-flex h-10 items-center gap-1.5 rounded-xl px-3.5 text-sm font-semibold transition"
                        class:bg-indigo-50="activeMenu === 'resources'"
                        class:text-indigo-700="activeMenu === 'resources'"
                        class:text-slate-700="activeMenu !== 'resources'"
                        class:hover:bg-slate-100="activeMenu !== 'resources'"
                        class:hover:text-slate-950="activeMenu !== 'resources'"
                        class:dark:bg-indigo-500/10="activeMenu === 'resources'"
                        class:dark:text-indigo-300="activeMenu === 'resources'"
                        class:dark:text-slate-300="activeMenu !== 'resources'"
                        class:dark:hover:bg-white/5="activeMenu !== 'resources'"
                        class:dark:hover:text-white="activeMenu !== 'resources'"
                    >
                        {resourcesLabel}

                        <span class="icon-[lucide--chevron-down] h-4 w-4 transition-transform duration-200" class:rotate-180="activeMenu === 'resources'"  aria-hidden="true" >
        </span>
        </button>
        <a
                        href="{pricingHref}"
                        class="inline-flex h-10 items-center rounded-xl px-3.5 text-sm font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-300 dark:hover:bg-white/5 dark:hover:text-white"
                    >
                        {pricingLabel}
                    </a>
        </slot>
        </nav>
        <!-- Desktop actions -->
        <div class="hidden items-center gap-2 lg:flex">
        <slot name="actions">
        <a data-show="showStatus"
                        href="{statusHref}"
                        class="mr-1 inline-flex items-center gap-2 rounded-xl px-3 py-2 text-xs font-semibold text-slate-500 transition hover:bg-slate-100 hover:text-slate-950 dark:text-slate-400 dark:hover:bg-white/5 dark:hover:text-white"
                    >
        <span class="relative flex h-2 w-2">
        <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-60">
        </span>
        <span class="relative inline-flex h-2 w-2 rounded-full bg-emerald-500">
        </span>
        </span>

                        {statusLabel}
                    </a>
        <button data-show="showThemeToggle"
                        type="button"
                        data-wire-theme-toggle
                        aria-label="Toggle color theme"
                        title="Toggle color theme"
                        class="grid h-10 w-10 place-items-center rounded-xl border border-slate-200 bg-white text-slate-600 shadow-sm transition hover:border-slate-300 hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-300 dark:hover:border-white/20 dark:hover:bg-white/10 dark:hover:text-white"
                    >
        <span class="icon-[lucide--moon] h-4 w-4 dark:hidden" aria-hidden="true" >
        </span>
        <span class="icon-[lucide--sun] hidden h-4 w-4 dark:block" aria-hidden="true" >
        </span>
        <span class="sr-only">
                            Toggle color theme
                        </span>
        </button>
        <a data-show="showSignIn"
                        href="{signInHref}"
                        class="inline-flex h-10 items-center justify-center rounded-xl px-4 text-sm font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-200 dark:hover:bg-white/5 dark:hover:text-white"
                    >
                        {signInLabel}
                    </a>
        <a data-show="showPrimaryAction"
                        href="{primaryHref}"
                        class="group inline-flex h-10 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-4 text-sm font-bold text-white shadow-lg shadow-indigo-600/20 transition hover:-translate-y-0.5 hover:bg-indigo-500 hover:shadow-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950"
                    >
                        {primaryLabel}

                        <span class="icon-[lucide--arrow-right] h-4 w-4 transition-transform group-hover:translate-x-0.5" aria-hidden="true" >
        </span>
        </a>
        </slot>
        </div>
        <!-- Mobile actions -->
        <div class="flex items-center gap-2 lg:hidden">
        <button
                        type="button"
                        data-wire-theme-toggle
                        aria-label="Toggle color theme"
                        title="Toggle color theme"
                        class="grid h-10 w-10 place-items-center rounded-xl border border-slate-200 bg-white text-slate-600 shadow-sm transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white"
                    >
        <span class="icon-[lucide--moon] h-4 w-4 dark:hidden" aria-hidden="true" >
        </span>
        <span class="icon-[lucide--sun] hidden h-4 w-4 dark:block" aria-hidden="true" >
        </span>
        </button>
        <button
                        type="button"
                        @click="mobileMenuOpen = !mobileMenuOpen"
                        aria-label="{mobileMenuOpen ? 'Close navigation menu' : 'Open navigation menu'}"
                        aria-expanded="{mobileMenuOpen}"
                        aria-controls="public-mobile-navigation"
                        class="grid h-10 w-10 place-items-center rounded-xl border border-slate-200 bg-white text-slate-700 shadow-sm transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-200 dark:hover:bg-white/10 dark:hover:text-white"
                    >
        <span data-show="!mobileMenuOpen" class="icon-[lucide--menu] h-5 w-5" aria-hidden="true" >
        </span>
        <span data-show="mobileMenuOpen" class="icon-[lucide--x] h-5 w-5" aria-hidden="true" >
        </span>
        <span class="sr-only">
                            Toggle navigation
                        </span>
        </button>
        </div>
        </div>
        <!-- Outside-click backdrop -->
        <button type="button" data-show="activeMenu !== ''" @click="activeMenu = ''" aria-label="Close navigation menu" class="fixed inset-0 z-40 hidden cursor-default bg-transparent lg:block" class:hidden="activeMenu === ''" class:block="activeMenu !== ''" >
        </button>
        <!-- Desktop mega menus -->
        <div
                class="absolute inset-x-0 top-full z-50 max-lg:hidden"
                class:hidden="activeMenu === ''"
                class:block="activeMenu !== ''"
            >
        <div
                    class:hidden="activeMenu !== 'product'"
                    class:block="activeMenu === 'product'"
                >
        <ProductMegaMenu />
        </div>
        <div
                    class:hidden="activeMenu !== 'solutions'"
                    class:block="activeMenu === 'solutions'"
                >
        <SolutionsMegaMenu />
        </div>
        <div
                    class:hidden="activeMenu !== 'developers'"
                    class:block="activeMenu === 'developers'"
                >
        <DevelopersMegaMenu />
        </div>
        <div
                    class:hidden="activeMenu !== 'resources'"
                    class:block="activeMenu === 'resources'"
                >
        <ResourcesMegaMenu />
        </div>
        </div>
        <!-- Mobile navigation -->
        <div
                id="public-mobile-navigation"
                class="lg:hidden"
                class:hidden="!mobileMenuOpen"
                class:block="mobileMenuOpen"
            >
        <PublicMobileNavigation />
        </div>
        </header>
    }
}