Lenis Scroll-To Anchor Target
Wires data-anchor-target links to Lenis's scrollTo method with a custom quartic ease and configurable duration and offset. Clicking a link smoothly scrolls to the matching section id without any native anchor jump.
Setup — External Scripts
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lenis@1.2.3/dist/lenis.css">
<!-- JS -->
<script src="https://cdn.jsdelivr.net/npm/lenis@1.2.3/dist/lenis.min.js"></script>Code
<!-- Anchor Links -->
<nav class="nav">
<div class="nav__inner">
<span data-anchor-target="#pink" class="nav-link">Pink</span>
<span data-anchor-target="#yellow" class="nav-link">Yellow</span>
<span data-anchor-target="#blue" class="nav-link">Blue</span>
<span data-anchor-target="#orange" class="nav-link">Orange</span>
</div>
</nav>
<!-- Sections -->
<section id="pink" class="section-resource is--pink">
<div class="section-resource__inner">
<p class="section-resource__inner-p">#pink</p>
</div>
</section>
<section id="yellow" class="section-resource is--yellow">
<div class="section-resource__inner">
<p class="section-resource__inner-p">#yellow</p>
</div>
</section>
<section id="blue" class="section-resource is--blue">
<div class="section-resource__inner">
<p class="section-resource__inner-p">#blue</p>
</div>
</section>
<section id="orange" class="section-resource is--orange">
<div class="section-resource__inner">
<p class="section-resource__inner-p">#orange</p>
</div>
</section>.section-resource {
justify-content: center;
align-items: center;
height: 100vh;
display: flex;
}
.section-resource__inner {
background-color: #131313;
border: 1px solid #1f1f1f;
border-radius: 2em;
justify-content: center;
align-items: center;
width: 80%;
height: 60%;
padding-left: 5%;
padding-right: 5%;
display: flex;
position: relative;
}
.section-resource.is--pink { color: #ff98a1; }
.section-resource.is--yellow { color: #ffee98; }
.section-resource.is--blue { color: #98caff; text-align: center; }
.section-resource.is--orange { color: #ff4c24; }
.section-resource__inner-p {
text-align: center;
font-size: 5vw;
}
.nav {
z-index: 999;
pointer-events: none;
justify-content: center;
align-items: center;
width: 100%;
padding-top: 2vw;
padding-bottom: 2vw;
display: flex;
position: fixed;
bottom: 0;
left: 0;
}
.nav-link {
-webkit-user-select: none;
user-select: none;
padding-top: 1vw;
padding-bottom: 1vw;
font-size: 2vw;
transition-property: opacity;
transition-duration: .2s;
transition-timing-function: ease;
}
.nav-link:hover {
opacity: .5;
}
.nav__inner {
gap: 2vw;
pointer-events: auto;
background-color: #1f1f1f;
border-radius: 30vw;
justify-content: center;
align-items: center;
padding-left: 2vw;
padding-right: 2vw;
display: flex;
}// Lenis
const lenis = new Lenis({
autoRaf: true,
});
// Scroll-To Anchor Lenis
function initScrollToAnchorLenis() {
document.querySelectorAll("[data-anchor-target]").forEach(element => {
element.addEventListener("click", function () {
const targetScrollToAnchorLenis = this.getAttribute("data-anchor-target");
lenis.scrollTo(targetScrollToAnchorLenis, {
easing: (x) => (x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2),
duration: 1.2,
offset: 0 // Option to create an offset when there is a fixed navigation
});
});
});
}
// Initialize Scroll-To Anchor Lenis
document.addEventListener('DOMContentLoaded', () => {
initScrollToAnchorLenis();
});Guide
data-anchor-target
Add to any clickable element (link, button, span, etc.) with a value matching the target section's id including the # prefix — e.g. data-anchor-target="#orange" to scroll to <section id="orange">.
Target Sections
The element you want to scroll to needs a plain id attribute without the # — e.g. id="orange". Any element on the page can be a scroll target, not just sections.
Easing & Duration
The scrollTo call uses a custom quartic ease-in-out function and a 1.2s duration. Adjust duration to taste. Replace the easing function with any custom curve or use a named Lenis easing string.
Offset
The offset option (default 0) shifts the final scroll position by a fixed pixel amount. Set it to a negative value (e.g. -80) to account for a fixed navbar so the section heading is not hidden behind it.
Lenis Setup
This component requires Lenis to be initialised on the page. See the Lenis Smooth Scroll Setup component for the full initialisation pattern including GSAP ScrollTrigger integration.