About this concept
An organic navigation where the menu items are joined into a single continuous shape. Hovering (or focusing) an item spreads its neighbours apart and stretches the connecting “necks” between the pills, so the whole bar feels like one living, elastic object rather than a row of separate buttons.
Built for the Holos app · Holos teal on near-black · Montserrat UI / Fraunces headings.
What’s gone into it
True vector geometry (not a blur filter)
Early drafts used an SVG “gooey” blur filter to fuse the pills, but that reads soft and raster-y. This version generates one real SVG path every frame: each pill is a flat-topped stadium, and each neck is a pair of cubic Bézier curves that pinch to a waist and meet the pills with horizontal tangents (so the joins are perfectly smooth).
The neck maths came from a hand-drawn reference. With R = cap radius (= half the bar height) and s = half the gap between two pills:
- The waist always pinches to a thickness of
R/3— constant, no matter how far a neck stretches. - Pill-side Bézier handle =
⅔·s. - Waist-side Bézier handle =
s − R.
So when a neck stretches on hover, both the span and its control handles grow by those rules — that’s what keeps the curve graceful at every length.
Motion & feel
- A single ease-in-out tween drives both the neck spread and the re-centering, so the bar accelerates in and settles out (no snapping, no endless crawl).
- Only the two necks beside the active item open; the rest stay at rest.
- The whole bar stays horizontally centered as it grows.
- Labels sit dimmed by default and brighten toward opaque based on cursor proximity.
- Two teal glows, both clipped inside the shape: one follows the mouse, plus a subtle constant glow on the active item.
- The selected item is shown in teal with an underline.
Concept vs. production
The two mockups share one reusable component. The Concept is the pure visual study (click to select). The Production-ready one wraps the same visuals in real navigation plumbing: semantic <a> links, full keyboard support (Tab + Enter) with a focus ring, active state driven by the URL, prefers-reduced-motion, a resize re-measure, and a tappable fallback menu on narrow screens.
Editing
Everything is in one self-contained file. All tuning lives in the constants block at the top of the OrganicNav() function:
| Constant | Default | Controls |
|---|---|---|
H | 48 | Pill height. Drives cap radius R = H/2 and the entire waist proportion. |
PAD | 2.4 | Horizontal padding inside each pill (space around the text). |
GAP | 1.35·H | Resting neck length between pills. |
SPREAD | 1.65·H·0.7 | Extra gap added beside the active item on hover. |
DUR | 650 | Tween duration (ms). Higher = silkier. Auto-set to 0 under reduced-motion. |
BASE_OP | 0.72 | Resting text opacity (kept high for readability). Brightens toward 1 near the cursor. |
NEAR / FAR | 70 / 200 | Cursor distance for full / zero text brightening. |
UL_MAX | 40 | Max width of the selected-item underline. |
HIT_X | 10 | How far the clickable area extends past each pill. |
Glow size lives on the two <circle> radii (mouse glow r=212, active glow r=150) and its strength on the gradient stop-opacities (0.31 / 0.13) plus .glow-active opacity (0.32).
Colours
Swap the brand colours in the :root block at the top of the stylesheet:
--bg: #011012; /* page background */
--shape: #031d22; /* the connected pill shape */
--ink: #fffcfb; /* label text */
--teal: #279DAF; /* selected text + underline + glow */
Implementing
The component API
The nav is a single factory function. Drop a host element on the page, then:
OrganicNav(hostElement, {
id: 'prod', // unique prefix for this instance's SVG ids
items: [ // your menu
{ label: 'Directory', href: '/directory' },
{ label: 'Map', href: '/map' },
/* ... */
],
selectedIndex: 0, // initial active item
asLinks: true, // real <a> links + keyboard + URL routing
responsive: true // resize re-measure + mobile fallback menu
});
You can place more than one on a page — just give each a unique id (it namespaces the SVG gradient/clip IDs so instances don’t collide).
In Webflow
- Add an HTML Embed containing a host
<div id="nav"></div>, the component<script>, and the small CSS block (or move the CSS into the page/site styles). - Montserrat & Fraunces are already loaded in Holos, so you can drop the Google-Fonts
<link>. - The SVG reserves a fixed footprint (sized for the widest hover state) so spreading never reflows the logo or account menu beside it.
- For the lab/CDN pattern, this can also be split into
organic-nav.css+organic-nav.jsand loaded via the standard loader — say the word and I’ll package it that way.
Real (multi-page) routing
The production demo derives the active item from location.hash. For a normal multi-page site, point each item’s href at a real URL and match on the path instead — change indexFromHash() to compare location.pathname against item.href. Then the correct item lights up automatically on each page load.
Accessibility notes
- Items are real links: Tab to move, Enter to activate, with a teal focus ring;
aria-current="page"marks the active item. - Resting labels sit at
BASE_OP = 0.72for readability and brighten toward full opacity near the cursor; raise it further for maximum contrast. prefers-reduced-motioncollapses the spread animation to instant.- Below 720px the SVG hides and a tappable pill menu takes over, since the spread is hover-only.