ScrollToTopButton Component
· 3 min read ·
I created this component to add a fixed floating Back to Top button. It becomes visible after the user scrolls 300px vertically; on click it triggers a smooth scroll to the top while playing a short visual animation on the icon. I kept it simple without public props: customization (threshold, image) is done by editing the source (index.js). My goal was to keep it lightweight and easy to reuse.
Overview
Implemented features:
- Appears after 300px scroll (hard‑coded condition)
- Smooth scroll to top on click
- CSS animation on click (
fly+@keyframes flyUp) - Show/Hide using opacity + visibility
- Scroll listener with cleanup in
useEffect - Icon image can be swapped by changing the import
Component Code
Files structure
📁src
📁components
📁ScrollToTopButton
index.js
styles.module.css
Code
import React, { useState, useEffect } from "react";
import clsx from "clsx";
import styles from "./styles.module.css";
import buttontop from '@site/static/img/buttontop.webp'
export default function ScrollToTopButton() {
const [isVisible, setIsVisible] = useState(false);
const [fly, setFly] = useState(false);
useEffect(() => {
const toggleVisibility = () => {
if (window.scrollY > 300) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};
window.addEventListener("scroll", toggleVisibility);
return () => window.removeEventListener("scroll", toggleVisibility);
}, []);
const scrollToTop = () => {
setFly(true);
window.scrollTo({ top: 0, behavior: "smooth" });
setTimeout(() => setFly(false), 800);
};
return (
<div
className={clsx(
styles.scrollBtn,
isVisible && styles.show,
fly && styles.fly
)}
onClick={scrollToTop}
>
<img
src={buttontop}
alt="Back to top"
className="no-zoom"
width="30"
height="30"
/>
</div>
);
}
.scrollBtn {
position: fixed;
bottom: 30px;
right: 30px;
width: 60px;
height: 60px;
cursor: pointer;
opacity: 0;
visibility: hidden;
transition: opacity 0.4s, visibility 0.4s;
z-index: 1000;
}
.scrollBtn img {
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
transition: transform 0.3s;
}
.scrollBtn:hover img {
transform: scale(1.1);
}
/* Button visible after scroll */
.scrollBtn.show {
opacity: 1;
visibility: visible;
}
/* "Fly upward" animation */
.scrollBtn.fly img {
animation: flyUp 0.8s ease-in forwards;
}
@keyframes flyUp {
0% {
transform: translateY(0) scale(1);
opacity: 1;
}
100% {
transform: translateY(-300px) scale(0.6);
opacity: 0;
}
}
Installation
- Copy the
ScrollToTopButtonfolder intosrc/components/ - Import the component in your global layout (or a specific page)
- Ensure the image import works (
/static/img/buttontop.webp) - (Optional) Replace the image with your own
Configuration
- Threshold: edit
if (window.scrollY > 300)inindex.js - Image: replace the imported
buttontopimage
Customization
Change the image
- Place your image inside
static/img/ - Update the import in
index.js:
import buttontop from '@site/static/img/your-image.webp'
- The component uses it like:
<img
src={buttontop}
alt="Back to top"
width="30"
height="30"
/>
Edit styles
Open styles.module.css and adjust:
- Position: tweak
bottom/right - Size: adjust
width/height - Visual: modify
box-shadow - Animation: change
flyUpkeyframes
State & Behavior
isVisible: true whenwindow.scrollY > 300, else falsefly: toggled to true on click, reset after 800ms- Scroll listener: handles visibility logic and is cleaned up on unmount
Animations
Show/Hide
transition: opacity 0.4s, visibility 0.4s;
Click animation (flyUp)
@keyframes flyUp {
0% {
transform: translateY(0) scale(1);
opacity: 1;
}
100% {
transform: translateY(-300px) scale(0.6);
opacity: 0;
}
}
Full example
import React from 'react';
import Layout from '@theme-original/Layout';
import ScrollToTopButton from '@site/src/components/ScrollToTopButton';
export default function LayoutWrapper(props) {
return (
<>
<Layout {...props} />
<ScrollToTopButton />
</>
);
}
This article is part of the Design your site series:
Like, share or comment on BlueSky
Loading comments…
Related posts

Component Skill Bars & Circles
September 16, 2025

Component ImageOnClick
September 5, 2025

Component Tooltip
September 21, 2025

Tutorial Docusaurus React Live
October 1, 2025

Component Avatar
August 29, 2025

Component Columns
September 3, 2025
