A well-crafted back to top button is one of those tiny UX details that can dramatically improve navigation on long pages, blogs, documentation sites, and product listings. In this tutorial, we will build a lightweight, accessible, and smooth-scrolling back to top button using nothing more than plain HTML, CSS, and a few lines of JavaScript. No libraries, no bloat.
By the end of this guide, you will have a production-ready snippet you can drop into any project, including Express.js views, static sites, WordPress themes, or single-page applications.
What Is a Back to Top Button?
A back to top button is a small floating control, typically anchored to the bottom-right corner of the viewport, that scrolls the user back to the top of the page when clicked. It usually appears only after the user has scrolled down a certain distance, keeping the interface clean when it is not needed.
When Should You Use One?
- Long-form content such as blog posts, guides, and documentation
- Infinite scroll or lazy-loaded feeds
- Product listing pages with heavy filtering
- Mobile layouts where scrolling up manually is tedious
If your page fits in one or two viewport heights, you probably do not need one. Reserve it for pages taller than roughly four screens.

Step 1: Add the HTML
We will use a real <button> element rather than a <div> or <a>. This matters for accessibility and keyboard navigation.
<button id="backToTop" class="back-to-top" aria-label="Scroll back to top" title="Back to top">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M18 15l-6-6-6 6"/>
</svg>
</button>
Place this markup right before your closing </body> tag so it stays out of the main document flow.
Step 2: Style It With CSS
The CSS handles positioning, appearance, and the smooth fade transition when the button appears or disappears.
.back-to-top {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 48px;
height: 48px;
border: none;
border-radius: 50%;
background-color: #0d6efd;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
opacity: 0;
visibility: hidden;
transform: translateY(10px);
transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
z-index: 999;
}
.back-to-top.is-visible {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.back-to-top:hover,
.back-to-top:focus-visible {
background-color: #0b5ed7;
outline: 2px solid #ffffff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.back-to-top {
transition: opacity 0.2s ease;
transform: none;
}
}
Key CSS Choices Explained
- position: fixed keeps the button anchored while the user scrolls
- opacity + visibility creates a smooth fade without leaving an invisible click target
- focus-visible ensures keyboard users see a clear focus ring
- prefers-reduced-motion respects users who disable animations

Step 3: Add the JavaScript
We only need a small script to toggle the visible class and handle the scroll action.
(function () {
const button = document.getElementById('backToTop');
if (!button) return;
const SCROLL_THRESHOLD = 300; // pixels
let ticking = false;
function updateButton() {
if (window.scrollY > SCROLL_THRESHOLD) {
button.classList.add('is-visible');
} else {
button.classList.remove('is-visible');
}
ticking = false;
}
window.addEventListener('scroll', function () {
if (!ticking) {
window.requestAnimationFrame(updateButton);
ticking = true;
}
}, { passive: true });
button.addEventListener('click', function () {
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
window.scrollTo({
top: 0,
behavior: prefersReducedMotion ? 'auto' : 'smooth'
});
});
})();
Why This Script Is Fast
- Uses requestAnimationFrame to throttle scroll events
- Uses a passive scroll listener so the browser can optimize scrolling performance
- Falls back to instant scroll when the user prefers reduced motion
- Wrapped in an IIFE to avoid polluting the global scope
Accessibility Checklist
A back to top button should be usable by everyone, not just mouse users. Here is what to verify before shipping:
| Concern | Implementation |
|---|---|
| Keyboard focus | Use a native <button> element |
| Screen readers | Add aria-label=”Scroll back to top” |
| Motion sensitivity | Respect prefers-reduced-motion |
| Focus after scroll | Optionally move focus to the main heading |
| Contrast | Maintain at least 4.5:1 ratio for the icon |
Optional: Move Focus After Scrolling
For screen reader users, scrolling visually to the top does not move the focus. You can improve this by focusing your main landmark after the scroll completes:
button.addEventListener('click', function () {
window.scrollTo({ top: 0, behavior: 'smooth' });
const main = document.querySelector('main, h1');
if (main) {
main.setAttribute('tabindex', '-1');
main.focus({ preventScroll: true });
}
});

Design Best Practices in 2026
- Show it only when useful. Reveal after the user scrolls at least 300 to 500 pixels.
- Keep it small. Around 40 to 56 pixels wide, never dominating the viewport.
- Use a clear icon. An upward-pointing chevron or arrow is universally understood.
- Do not block content. On mobile, avoid overlapping call-to-action buttons or chat widgets.
- Match your brand. Use your primary color, but ensure contrast against varied backgrounds.
Common Mistakes to Avoid
- Using an
<a href="#top">withoutpreventDefault, which pushes an entry into browser history - Animating scroll with heavy JavaScript loops when
window.scrollTohandles it natively - Forgetting to test with keyboard-only navigation
- Placing the button over important interactive UI on small screens
FAQ
Do I need JavaScript for a back to top button?
Not necessarily. A pure anchor link pointing to #top combined with scroll-behavior: smooth on the html element works without any JavaScript. However, JavaScript gives you control over when the button appears and how it behaves on reduced-motion systems.
What is the ideal scroll distance before showing the button?
Between 300 and 500 pixels works well for most sites. On very long articles, you might delay it further to avoid distraction during the first fold of reading.
Is a back to top button good for SEO?
Indirectly, yes. It improves dwell time and reduces friction on long pages, which can positively impact engagement metrics. It has no direct ranking factor, but better UX typically correlates with better rankings.
Should the button appear on mobile?
Yes, especially on mobile, where scrolling long articles is tedious. Just be careful not to cover sticky navigation bars, floating chat icons, or cookie banners.
Can I use CSS scroll-behavior instead of JavaScript?
Absolutely. Add html { scroll-behavior: smooth; } and link to an anchor at the top of the page. The trade-off is that you cannot easily conditionally show or hide the button based on scroll position without JavaScript.
Wrapping Up
A back to top button is one of the highest-impact, lowest-effort UX improvements you can add to a long page. With the snippet above, you get smooth scrolling, accessibility support, reduced-motion handling, and optimized scroll performance in under 30 lines of code.
Drop it into your next project, tweak the colors to match your brand, and your readers will thank you the next time they finish a 3000-word article.
