Skip to content

Commit 6fe21fb

Browse files
feat: add animated back to top button component (#797)
* feat: Add animated back to top button component - Added BackToTopButton component with smooth scroll functionality - Integrated button in _app.tsx to appear on all pages - Added CSS animations for hover effects and smooth transitions - Button appears after scrolling 300px down the page - Responsive design with purple gradient hover effect * feat: Enhance BackToTopButton with performance optimizations and custom animations * move logic to useEffect --------- Co-authored-by: Azeez Elegbede <[email protected]> Co-authored-by: acethecreator <[email protected]>
1 parent d631a8a commit 6fe21fb

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React, { useState, useEffect, useCallback } from 'react';
2+
import Arrows from '../illustration/arrows';
3+
4+
const BackToTopButton: React.FC = () => {
5+
const [isVisible, setIsVisible] = useState(false);
6+
7+
useEffect(() => {
8+
let inThrottle = false;
9+
10+
const toggleVisibility = () => {
11+
if (window.pageYOffset > 300) {
12+
setIsVisible(true);
13+
} else {
14+
setIsVisible(false);
15+
}
16+
};
17+
18+
const throttledToggleVisibility = () => {
19+
if (!inThrottle) {
20+
toggleVisibility();
21+
inThrottle = true;
22+
setTimeout(() => {
23+
inThrottle = false;
24+
}, 150);
25+
}
26+
};
27+
28+
window.addEventListener('scroll', throttledToggleVisibility);
29+
30+
return () => {
31+
window.removeEventListener('scroll', throttledToggleVisibility);
32+
};
33+
}, []);
34+
35+
const scrollToTop = () => {
36+
window.scrollTo({
37+
top: 0,
38+
behavior: 'smooth',
39+
});
40+
};
41+
42+
return isVisible ? (
43+
<button
44+
onClick={scrollToTop}
45+
className="back-to-top-button fixed bottom-8 right-8 w-12 h-12 rounded-full border-none font-semibold flex items-center justify-center cursor-pointer overflow-hidden z-50 outline-none transition-all duration-300 ease-in-out transform hover:scale-95 active:scale-90"
46+
aria-label="Back to top"
47+
>
48+
<Arrows
49+
className="back-to-top-icon w-3 h-3 transition-all duration-300 ease-in-out"
50+
direction="up"
51+
fill="white"
52+
/>
53+
<span className="back-to-top-text absolute text-white text-xs opacity-0 whitespace-nowrap transition-all duration-300 ease-in-out">
54+
Back to Top
55+
</span>
56+
</button>
57+
) : null;
58+
};
59+
60+
export default BackToTopButton;

pages/_app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '../styles/globals.css';
22
import Navbar from '../components/Navbar/navbar';
33
import Footer from '../components/Footer/footer';
4+
import BackToTopButton from '../components/Buttons/BackToTopButton';
45
import { AppProps } from 'next/app';
56
import { useEffect, useState } from 'react';
67

@@ -18,6 +19,7 @@ function MyApp({ Component, pageProps }: AppProps) {
1819

1920
<Component {...pageProps} />
2021
<Footer />
22+
<BackToTopButton />
2123
</div>
2224
);
2325
}

styles/globals.css

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,25 @@ backdrop-filter: blur(10px); */
259259
.hoverEffect:hover {
260260
transform: scale(1.1); /* Scale the image by 10% on hover */
261261
}
262+
263+
/* Back to Top Button Styles - Custom animations not handled by Tailwind */
264+
.back-to-top-button {
265+
background-color: rgb(20, 20, 20);
266+
box-shadow: 0px 0px 0px 4px rgba(180, 160, 255, 0.253);
267+
}
268+
269+
.back-to-top-button:hover {
270+
width: 140px;
271+
border-radius: 50px;
272+
background-color: rgb(181, 160, 255);
273+
}
274+
275+
.back-to-top-button:hover .back-to-top-icon {
276+
transform: translateY(-200%);
277+
opacity: 0;
278+
}
279+
280+
.back-to-top-button:hover .back-to-top-text {
281+
font-size: 13px;
282+
opacity: 1;
283+
}

0 commit comments

Comments
 (0)