A floating button that appears after scrolling and smoothly scrolls the page back to the top. Available in 4 variants: default circle, pill with text, minimal icon-only, and progress indicator.
Preview
Default
Pill
Minimal
Progress (50%)
Text (50%)
Installation
Usage
import { ScrollToTop } from "@/components/ui/scroll-to-top"
export default function Page() {
return (
<main>
{/* Your page content */}
<ScrollToTop />
</main>
)
}Variants
Default
Circular button with arrow icon. Supports 3 sizes: sm, md, lg.
import { ScrollToTop } from "@/components/ui/scroll-to-top"
<ScrollToTop />
<ScrollToTop size="sm" />
<ScrollToTop size="lg" />Pill
Elongated button with customizable text label.
import { ScrollToTopPill } from "@/components/ui/scroll-to-top"
<ScrollToTopPill />
<ScrollToTopPill label="Back to top" />Minimal
Icon-only button without background. Subtle and unobtrusive.
import { ScrollToTopMinimal } from "@/components/ui/scroll-to-top"
<ScrollToTopMinimal />Progress
Circular button with scroll progress indicator. Shows how far user has scrolled on the page.
import { ScrollToTopProgress } from "@/components/ui/scroll-to-top"
<ScrollToTopProgress />
<ScrollToTopProgress progressColor="#10b981" />
<ScrollToTopProgress strokeWidth={4} />Examples
Custom Threshold
Adjust the scroll distance before the button appears.
// Button appears after scrolling 500px
<ScrollToTop threshold={500} />
// Button appears after scrolling 100px
<ScrollToTop threshold={100} />Custom Position
Override default positioning with custom classes.
// Bottom left corner
<ScrollToTop className="left-6 right-auto" />
// Higher position
<ScrollToTop className="bottom-20" />Using the Hook
Use the useScrollToTop hook for custom implementations.
import { useScrollToTop } from "@/components/ui/scroll-to-top"
function CustomScrollButton() {
const { isVisible, scrollProgress, scrollToTop } = useScrollToTop(300)
if (!isVisible) return null
return (
<button onClick={() => scrollToTop()}>
{Math.round(scrollProgress)}% scrolled - Click to go up
</button>
)
}Props
ScrollToTop (Default)
| Prop | Type | Default | Description |
|---|---|---|---|
| threshold | number | 300 | Scroll distance (px) before button appears |
| behavior | ScrollBehavior | "smooth" | Scroll animation behavior |
| size | "sm" | "md" | "lg" | "md" | Button size |
| className | string | - | Additional CSS classes |
ScrollToTopPill
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | "Scroll to top" | Button text label |
| threshold | number | 300 | Scroll distance (px) before button appears |
| className | string | - | Additional CSS classes |
ScrollToTopProgress
| Prop | Type | Default | Description |
|---|---|---|---|
| progressColor | string | primary | Progress circle color |
| progressBgColor | string | muted | Progress background circle color |
| strokeWidth | number | 3 | Circle stroke width in px |
| threshold | number | 300 | Scroll distance (px) before button appears |
useScrollToTop Hook
Use the hook for custom scroll-to-top implementations:
import { useScrollToTop } from "@/components/ui/scroll-to-top"
function MyComponent() {
const {
isVisible, // boolean - whether threshold is passed
scrollProgress, // number 0-100 - scroll progress percentage
scrollToTop, // (behavior?: ScrollBehavior) => void
} = useScrollToTop(300) // threshold in px
return (
<div>
<p>Progress: {scrollProgress.toFixed(0)}%</p>
{isVisible && (
<button onClick={() => scrollToTop("smooth")}>
Go to top
</button>
)}
</div>
)
}Features
- 4 Variants — default, pill, minimal, and progress styles
- Smooth animations — fade and slide transitions on show/hide
- Configurable threshold — control when button appears
- Progress indicator — visual scroll progress feedback
- Accessible — proper aria-label and focus states
- Hook export — build custom implementations
- Customizable — override position, colors, and more via className