Skip to main content

ScrollToTopButton Component

· 3 min read ·
Docux
Curious explorer, a bit of a mad experimenter, and a bit of a contributor.

Developer Development License: MIT AI 25%

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

  1. Copy the ScrollToTopButton folder into src/components/
  2. Import the component in your global layout (or a specific page)
  3. Ensure the image import works (/static/img/buttontop.webp)
  4. (Optional) Replace the image with your own

Configuration

  • Threshold: edit if (window.scrollY > 300) in index.js
  • Image: replace the imported buttontop image

Customization

Change the image

  1. Place your image inside static/img/
  2. Update the import in index.js:
import buttontop from '@site/static/img/your-image.webp'
  1. 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 flyUp keyframes

State & Behavior

  • isVisible: true when window.scrollY > 300, else false
  • fly: 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 />
</>
);
}
Back to top