Header

The marketing site header: a logo/brand mark, a center nav slot, an end slot (usually login/signup), a dark mode toggle, and a built-in mobile hamburger menu. Place it as the first thing on the page, before <Base>.

Properties

Name
Default
Description
product
Product slug (e.g. "blogs"). Derives the default logo and fetches the cloud updates banner on hyvor.com.
instance
"https://hyvor.com"
Base URL used to build the default logo and updates banner.
name
"HYVOR"
The main name, usually "HYVOR".
subName
The sub name of the product. Ex: "Design"
logo
URL/path to the logo image. Overrides the product-derived default.
darkToggle
true
Whether to show the dark mode toggle button.
max
false
Set the width for 1440px of the header.
menuLabel
"Menu"
aria-label for the mobile hamburger menu button. Translate this when localizing the page.
logoAltText
"Logo"
The word appended to the logo's alt text (e.g. "HYVOR Design Logo"). Translate this when localizing the page - name/subName are product-defined and stay as-is.

Slots

Name
Description
center
The content in the center of the header. Usually, the navigation links like "Docs", "Pricing", etc., built with HeaderNavLink. You can also use Dropdowns here (e.g. for a "Resources" menu).
end
The content in the end of the header. Usually, the login/signup buttons.

Mobile Navigation

On mobile and tablets (<=992px), content in both center and end slots will be hidden, and a hamburger menu will be shown instead. The hamburger menu opens a dropdown with the content of both slots (with a divider between them), and its icon switches from a hamburger to a close (X) icon while open. Clicking any link inside the menu closes it automatically.

The header also gains a bottom border once the page is scrolled, so it stays visually separated from the content beneath it.

HeaderNavLink is a pill-shaped nav link meant to be used inside the center slot (and inside dropdown menus placed there). It renders an <a> when given an href, or a <span> otherwise, so it can also be used as a Dropdown trigger (e.g. a "Resources" link that opens a submenu).

Name
Default
Description
href
The link URL. When omitted, the link renders as a clickable span.
active
false
Highlights the link as the current page.
menu
false
Compact style for links inside a Dropdown's menu (e.g. the header's mobile menu). Implied automatically when description is given.
Name
Description
start
Content before the label, usually an icon. Renders inside a tinted icon box when description is given.
children
The link label.
end
Content after the label, usually a caret icon. Not used when description is given.
description
A one-line description shown under the label. Switches to a richer layout (icon box, bold title, muted description) for menus needing more than a label.

Example

<script>
    import Header from "@hyvor/design/marketing/Header.svelte";
    import { HeaderNavLink } from "@hyvor/design/marketing";
    import { Button, Dropdown } from "@hyvor/design/components";
    import IconCaretDown from "@hyvor/icons/IconCaretDown";
    import IconPalette from "@hyvor/icons/IconPalette";
    import IconPuzzle from "@hyvor/icons/IconPuzzle";

    import logo from '../img/logo.svg';

    let resourcesOpen = $state(false);
</script>

<Header
    logo={logo}
    subName="Talk"
>

    {#snippet center()}
        <HeaderNavLink href="/docs" active={page.url.pathname.startsWith('/docs')}>
            Docs
        </HeaderNavLink>
        <HeaderNavLink href="/pricing" active={page.url.pathname === '/pricing'}>
            Pricing
        </HeaderNavLink>

        <Dropdown bind:show={resourcesOpen} contentPadding={8}>
            {#snippet trigger()}
                <HeaderNavLink active={resourcesOpen}>
                    Resources
                    {#snippet end()}
                        <IconCaretDown size={11} />
                    {/snippet}
                </HeaderNavLink>
            {/snippet}
            {#snippet content()}
                <HeaderNavLink href="/themes" active={page.url.pathname === '/themes'}>
                    {#snippet start()}<IconPalette size={15} />{/snippet}
                    Themes
                    {#snippet description()}Blog themes to match your brand{/snippet}
                </HeaderNavLink>
                <HeaderNavLink href="/integrations" active={page.url.pathname.startsWith('/integrations')}>
                    {#snippet start()}<IconPuzzle size={15} />{/snippet}
                    Integrations
                    {#snippet description()}Connect with your favorite tools{/snippet}
                </HeaderNavLink>
            {/snippet}
        </Dropdown>
    {/snippet}

    {#snippet end()}
        <div>
            <Button as="a" href="/login" color="invisible">
                Login
            </Button>
            <Button as="a" href="/signup">
                Signup
            </Button>
        </div>
    {/snippet}

</Header>

HeaderLanguageToggle

HeaderLanguageToggle is for marketing sites that serve each language on its own URL (e.g. a SvelteKit [[lang]] route param) rather than switching language client-side on one page. Use it inside the center slot, next to your HeaderNavLinks. It's not related to InternationalizationService/LanguageToggle, which swap translated strings in place on a single page; use that instead if you don't have per-language routes. See it in action in the header of /test.

Properties

Name
Default
Description
languages
An array of { code, flag, name }.
current
Code of the language the current page is showing.
href
(code: string) => string. Returns the URL for switching to the given language code. Build it however your routing works, e.g. with buildLocalizedUrl below.
showName
false
Shows the language name next to the flag in the trigger, not just the flag.
align
"center"
Passed to the underlying Dropdown.
position
"bottom"
Passed to the underlying Dropdown.
label
"Change language"
aria-label for the trigger button. Translate this when localizing the page.

buildLocalizedUrl

A small helper for the common convention where the default language is served without a prefix and every other language is served under /{code}:

buildLocalizedUrl(path: string, currentLang: string, targetLang: string, defaultLang: string): string

buildLocalizedUrl('/pricing', 'en', 'fr', 'en') // '/fr/pricing'
buildLocalizedUrl('/fr/pricing', 'fr', 'en', 'en') // '/pricing'
buildLocalizedUrl('/fr', 'fr', 'en', 'en') // '/'

If your app routes languages differently (a subdomain per locale, a query param, ...), skip buildLocalizedUrl and build href yourself. HeaderLanguageToggle doesn't assume any particular URL scheme.

Example

<script>
    import { HeaderLanguageToggle, buildLocalizedUrl } from "@hyvor/design/marketing";
    import { page } from '$app/stores';

    const languages = [
        { code: 'en', flag: '🇬🇧', name: 'English' },
        { code: 'fr', flag: '🇫🇷', name: 'Français' }
    ];
    const defaultLanguage = 'en';

    const currentLang = $derived(
        languages.find((l) => l.code === $page.url.pathname.split('/')[1])?.code ?? defaultLanguage
    );
</script>

<Header product="blogs">
    {#snippet center()}
        <HeaderNavLink href="/pricing">Pricing</HeaderNavLink>
        <HeaderNavLink href="/docs">Docs</HeaderNavLink>

        <HeaderLanguageToggle
            {languages}
            current={currentLang}
            href={(code) => buildLocalizedUrl($page.url.pathname, currentLang, code, defaultLanguage)}
        />
    {/snippet}
</Header>