# Back To Top

> A React back to top button that appears on long pages, rings with your reading progress and takes you, and your focus, back up.

- Type: React component (Navigation)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add back-to-top`
- Docs: https://wingo-ui.com/components/back-to-top

## Interaction

Scroll past the threshold and the button pops in on a quick spring, a thin ring around it filling as you read. Click or tap it to glide back to the top; once the scroll settles, focus moves to the page title so keyboard and screen reader users land there too (scroll away mid-way and focus stays put). Tab to it for a focus ring outside the progress ring, and press Enter or Space. With showOn="scroll-up" it stays out of the way while you read down and comes back the moment you flick up. On a phone it is 48px, sits above the bottom tab bar and clears the home indicator. Under reduced motion it only fades and the jump is instant.

## Installation

```bash
npx wingo-ui@latest add back-to-top
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/back-to-top` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/ui/back-to-top.tsx`

npm dependencies: `npm i motion lucide-react`

Wingo UI dependencies (installed automatically):

- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))
- [useScrollState](https://wingo-ui.com/components/use-scroll-state) ([Markdown](https://wingo-ui.com/components/use-scroll-state.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))
- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
import type { ReactNode } from "react"
import { BackToTop } from "@/components/ui/back-to-top"

export function GhidEFactura({ children }: { children: ReactNode }) {
  return (
    <main>
      <h1>Guide: send your first invoice in 12 steps</h1>
      {children}
      <BackToTop label="Back to the top" showOn="scroll-up" />
    </main>
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `threshold?` | `number` | `400` | Pixels scrolled before it appears. 0 shows it on any scroll. Content shorter than this never shows it. |
| `showOn?` | `"scroll" \| "scroll-up"` | `"scroll"` | scroll: whenever you are past the threshold. scroll-up: only while scrolling up past it (and at the very end), out of the way while reading down, like Safari's toolbars. The recommendation for phones. |
| `progress?` | `boolean` | `true` | A 2px ring around the button that fills with reading progress, from 12 o'clock. It follows the scroll every frame without re-rendering. |
| `variant?` | `"surface" \| "solid" \| "glass"` | `"surface"` | surface: the popover surface with a floating shadow, readable over anything. solid: filled with the tone. glass: a translucent blurred surface for photo-heavy pages. |
| `tone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | Colors the progress ring, and the fill of the solid variant. |
| `color?` | `string` | `""` | Any CSS color. Replaces the tone for the ring and the solid fill. Leave empty to use the tone. |
| `size?` | `"sm" \| "md" \| "lg"` | `"md"` | 40 / 48 / 56px. A floating button never drops below 44px on touch screens, so sm grows to 44px there. |
| `radius?` | `"md" \| "lg" \| "full"` | `"full"` | Corner shape, scaled with the size like the button's. The progress ring follows it. |
| `label?` | `string` | `"Back to top"` | The accessible name, and the text of the extended pill when showLabel is on. |
| `showLabel?` | `boolean` | `false` | An extended pill with the label beside the arrow, instead of an icon-only button. |
| `icon?` | `ReactNode` |  | Replaces the default ArrowUp icon. It nudges up 2px on hover with a mouse. |
| `position?` | `"fixed" \| "sticky" \| "absolute"` | `"fixed"` | fixed: pinned to the viewport. sticky: render it as the last child of a scroll container and it pins to that container's bottom (panels, cards, demos). absolute: inside a positioned parent. |
| `side?` | `"end" \| "start" \| "center"` | `"end"` | Logical side, so end is on the left in right-to-left layouts. |
| `offset?` | `number` | `16` | Pixels from the edges. Added to the bottom safe area and to --bottom-bar-offset, which a bottom tab bar sets. |
| `smooth?` | `boolean` | `true` | Smooth scroll back to the top. Always instant when the user prefers reduced motion. The demo's readout shows it. |
| `focusTarget?` | `string \| HTMLElement \| null` | `"h1"` | Gets focus once the scroll settles: a selector looked up inside the scroll container, or an element. Falls back to the container, then the body; elements that are not focusable get a temporary tabindex. If you scroll away before the top is reached, focus stays put. null leaves focus alone. |
| `scrollTarget?` | `HTMLElement \| Window \| RefObject<HTMLElement \| null> \| null` |  | What scrolls. Default: the nearest ScrollContainerProvider, else (sticky and absolute) the nearest scrolling ancestor, else the window. |
| `onClick?` | `(event: MouseEvent<HTMLButtonElement>) => void` |  | Runs before scrolling. Call event.preventDefault() to cancel the scroll. |
| `classNames?` | `Partial<Record<"button" \| "ring" \| "icon" \| "label", string>>` |  | Extra classes for the inner parts. |
| `className?` | `string` |  | Extra classes for the positioned wrapper. Other props go to it too. |

## Examples

- **Extended pill**: showLabel with a short custom label: "Top" next to the arrow.
- **Only when scrolling up**: showOn="scroll-up" keeps it out of the way while reading down, like Safari's toolbars. The phone recommendation.
- **Variants over photos**: surface, solid and glass, each readable over any content.
- **Sizes and radii**: 40 / 48 / 56px with md, lg and full corners. The ring follows the shape.
- **Brand ring**: tone="brand" on a marketing page, with a custom icon and label.
- **Above a bottom tab bar**: --bottom-bar-offset from the tab bar lifts the button above it, no props needed.

## See also

- [useScrollState](https://wingo-ui.com/components/use-scroll-state) ([Markdown](https://wingo-ui.com/components/use-scroll-state.md))
- [Scroll Progress](https://wingo-ui.com/components/scroll-progress) ([Markdown](https://wingo-ui.com/components/scroll-progress.md))
- [Table Of Contents](https://wingo-ui.com/components/table-of-contents) ([Markdown](https://wingo-ui.com/components/table-of-contents.md))
- [FAB](https://wingo-ui.com/components/fab) ([Markdown](https://wingo-ui.com/components/fab.md))
- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))

---

Canonical: https://wingo-ui.com/components/back-to-top
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
