diff --git a/src/components/ScrollToTopButton/index.js b/src/components/ScrollToTopButton/index.js
new file mode 100644
index 00000000..089392ff
--- /dev/null
+++ b/src/components/ScrollToTopButton/index.js
@@ -0,0 +1,29 @@
+import React, { useState, useEffect } from "react";
+import styles from "./styles.module.css";
+
+export default function ScrollToTopButton() {
+ const [visible, setVisible] = useState(false);
+
+ useEffect(() => {
+ const onScroll = () => setVisible(window.scrollY > 300);
+ window.addEventListener("scroll", onScroll, { passive: true });
+ return () => window.removeEventListener("scroll", onScroll);
+ }, []);
+
+ const scrollToTop = () => {
+ window.scrollTo({ top: 0, behavior: "smooth" });
+ };
+
+ if (!visible) return null;
+
+ return (
+
+ );
+}
diff --git a/src/components/ScrollToTopButton/styles.module.css b/src/components/ScrollToTopButton/styles.module.css
new file mode 100644
index 00000000..6ffa81d9
--- /dev/null
+++ b/src/components/ScrollToTopButton/styles.module.css
@@ -0,0 +1,26 @@
+.scrollToTop {
+ position: fixed;
+ bottom: 2rem;
+ right: 2rem;
+ z-index: 999;
+ width: 2.5rem;
+ height: 2.5rem;
+ border-radius: 50%;
+ border: none;
+ background-color: var(--ifm-color-primary);
+ color: #fff;
+ font-size: 1.2rem;
+ line-height: 1;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ transition: background-color 0.2s, opacity 0.2s, transform 0.2s;
+ opacity: 0.85;
+}
+
+.scrollToTop:hover {
+ opacity: 1;
+ transform: translateY(-2px);
+}
diff --git a/src/theme/Root.js b/src/theme/Root.js
new file mode 100644
index 00000000..54c81c3f
--- /dev/null
+++ b/src/theme/Root.js
@@ -0,0 +1,11 @@
+import React from "react";
+import ScrollToTopButton from "@site/src/components/ScrollToTopButton";
+
+export default function Root({ children }) {
+ return (
+ <>
+ {children}
+
+ >
+ );
+}