Free Webflow components / Effect: stretchy nav selector pill
Webflow navigation with a sliding pill
A free nav hover effect for Webflow: a pill stretches to the link you point at, then settles. Copy it, press ⌘V in the Designer, and edit the links.
- JavaScript
- Responsive
- Hover states
What you receive in Webflow
- 13 native elements and 7 classes.
- Breakpoints: mobile landscape (767px).
- States: hover.
- 2 Embed elements keep the CSS or script that Webflow cannot express. To edit an Embed, you must have a paid Webflow site plan.
How to paste it
- Click Copy for Webflow.
- Open your page in the Webflow Designer.
- Press ⌘V or Ctrl+V.
HTML
<section class="ns">
<div class="ns-inner">
<nav class="ns-nav" aria-label="Sections">
<span class="ns-pill" aria-hidden="true"></span>
<a class="ns-item is-active" href="#" aria-current="page">Overview</a>
<a class="ns-item" href="#">Features</a>
<a class="ns-item" href="#">Integrations</a>
<a class="ns-item" href="#">Pricing</a>
<a class="ns-item" href="#">FAQ</a>
</nav>
<p class="ns-text">Hover the menu: the pill stretches toward the item, then settles. Click to make it the selected one.</p>
</div>
</section>
<style>
.ns { font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; background: #18181b; color: #fafafa; padding: 120px 24px; }
.ns-inner { max-width: 760px; margin: 0 auto; text-align: center; }
.ns-nav { position: relative; display: inline-flex; gap: 4px; padding: 6px; border-radius: 999px; background: #27272a; border: 1px solid #3f3f46; }
.ns-pill { position: absolute; top: 6px; left: 0; height: calc(100% - 12px); width: 0; border-radius: 999px; background: #fafafa; opacity: 0; transition: left 0.38s cubic-bezier(0.6, 0, 0.2, 1), width 0.38s cubic-bezier(0.6, 0, 0.2, 1), opacity 0.2s ease; }
.ns-item { position: relative; z-index: 1; padding: 12px 20px; border-radius: 999px; font-size: 15px; font-weight: 700; color: #a1a1aa; text-decoration: none; transition: color 0.25s ease; }
.ns-item:hover { color: #fafafa; }
.ns-item.is-active { color: #18181b; background: #fafafa; }
.ns-item:focus-visible { outline: 2px solid #a78bfa; outline-offset: 2px; }
.ns-js .ns-item.is-active { background: transparent; }
.ns-js .ns-pill { opacity: 1; }
.ns-js .ns-item.is-under { color: #18181b; }
.ns-js .ns-item.is-active:not(.is-under) { color: #a1a1aa; }
.ns-text { font-size: 16px; line-height: 1.6; color: #71717a; margin: 40px 0 0; }
@media (max-width: 767px) { .ns { padding: 80px 12px; } .ns-item { padding: 10px 12px; font-size: 13px; } }
</style>
<script>
document.querySelectorAll(".ns-nav").forEach(function (nav) {
var pill = nav.querySelector(".ns-pill");
var items = nav.querySelectorAll(".ns-item");
var active = nav.querySelector(".ns-item.is-active") || items[0];
var current = null, timer;
document.documentElement.classList.add("ns-js");
function place(el, stretch) {
if (current) current.classList.remove("is-under");
el.classList.add("is-under");
var from = current;
current = el;
var l = el.offsetLeft, w = el.offsetWidth;
clearTimeout(timer);
if (stretch && from && from !== el) {
// stretch over both items first, then shrink onto the new one
var a = Math.min(from.offsetLeft, l), b = Math.max(from.offsetLeft + from.offsetWidth, l + w);
pill.style.left = a + "px"; pill.style.width = (b - a) + "px";
timer = setTimeout(function () { pill.style.left = l + "px"; pill.style.width = w + "px"; }, 170);
} else { pill.style.left = l + "px"; pill.style.width = w + "px"; }
}
items.forEach(function (it) {
it.addEventListener("pointerenter", function () { place(it, true); });
it.addEventListener("focus", function () { place(it, true); });
it.addEventListener("click", function (e) {
if (it.getAttribute("href") === "#") e.preventDefault();
active.classList.remove("is-active"); active.removeAttribute("aria-current");
active = it; it.classList.add("is-active"); it.setAttribute("aria-current", "page");
});
});
nav.addEventListener("pointerleave", function () { place(active, true); });
place(active, false);
window.addEventListener("resize", function () { place(current || active, false); });
});
</script>
More examples
Questions
Can I add more links?
Yes. Duplicate a link in the Navigator. The script measures the links when the page loads and when the window resizes.
What happens on click?
The clicked link becomes the selected one, and the pill returns to it when the pointer leaves.
Is this effect component free?
Yes. Copy it with no account and use it on client sites and your own sites.
Does it work on the free Webflow plan?
Yes. It pastes on every Webflow plan, including Starter. If it includes an Embed element, editing that Embed's code needs a paid site plan.