Navigation

These pieces build the floating navigation that defines Joy's look: a pill-shaped topbar and a pill-shaped dock. They're optional — a site can use only the content classes (cards, buttons, forms) with none of this.

joy.js looks for these elements automatically on DOMContentLoaded, by the ids below. If one is missing from the page, that piece of setup just does nothing — you don't need to remove any code, only skip the markup.

Topbar

<nav class="joy-topbar joy-glass joy-rounded-pill">
    <a href="/"><img src="/logo.png" alt="Brand" style="width:26px;height:26px;"></a>
    <button type="button" class="joy-btn joy-btn-ghost joy-btn-icon" id="joy-theme-toggle"><i class="ph ph-moon"></i></button>
    <div id="joy-topbar-auth-slot">
        <a href="/login" class="joy-btn joy-btn-ghost"><i class="ph ph-sign-in"></i><span>Log in</span></a>
        <a href="/register" class="joy-btn joy-btn-solid"><i class="ph ph-user-plus"></i><span>Sign up</span></a>
    </div>
</nav>
PieceRole
#joy-theme-togglewires up JoyTheme.toggle() on click, if present
#joy-topbar-auth-slotswapped by JoyAuth.renderLoggedIn(user) after a login, no reload needed

User menu (topbar dropdown)

<div class="joy-user-menu" id="joy-user-menu">
    <button type="button" class="joy-btn joy-btn-ghost" id="joy-user-trigger" aria-haspopup="true">
        <img src="/avatar.png" alt="" class="joy-user-avatar">
        <span>Jane Doe</span>
        <i class="ph ph-caret-down"></i>
    </button>
    <div class="joy-user-dropdown" id="joy-user-dropdown">
        <a href="/profile" class="joy-user-dropdown-item"><i class="ph ph-user"></i> My profile</a>
        <a href="/logout" class="joy-user-dropdown-item"><i class="ph ph-sign-out"></i> Log out</a>
    </div>
</div>

All three ids (#joy-user-menu, #joy-user-trigger, #joy-user-dropdown) are required together for the open/close toggle to work.

Bottom dock

The main floating navigation — on desktop, each item expands on hover to show its label; on mobile (≤600px) it collapses into a ‹ Icon Label › selector with arrows, and swiping switches tabs.

<nav class="joy-dock joy-glass">
    <button type="button" class="joy-dock-arrow joy-dock-prev" aria-label="Previous"><i class="ph ph-caret-left"></i></button>
    <a href="/" class="joy-dock-item is-active"><i class="ph ph-house"></i><span class="joy-dock-label">Home</span></a>
    <a href="/products" class="joy-dock-item"><i class="ph ph-squares-four"></i><span class="joy-dock-label">Products</span></a>
    <a href="/about" class="joy-dock-item"><i class="ph ph-info"></i><span class="joy-dock-label">About</span></a>
    <button type="button" class="joy-dock-arrow joy-dock-next" aria-label="Next"><i class="ph ph-caret-right"></i></button>
</nav>
DetailBehavior
Active itemthe .is-active class on one .joy-dock-item
Clicking a linknavigates normally — the dock never intercepts a click in plain anchor mode
Tapping the active tab (mobile)opens a "jump to" popup, built automatically, listing every tab
Dragging on mobilefollows your finger in real time, with an axis lock so it doesn't fight vertical scrolling

The mobile dock uses touch-action and dedicated touch listeners — if your page already has its own swipe/carousel system, test the two together before shipping.