Skip to main content
BM

BackToTop

A button that appears once a page is scrolled down, and takes the reader and their focus back to the top.

View source on GitHub

BackToTopExample.tsx
import { BackToTop } from "@/components/BackToTop";

export function BackToTopExample() {
  return <BackToTop placement="inline" visible showLabel />;
}

Examples

Variants

With its label

Announced as: “Back to top, button”

Sizes

On every page

The site shell shows one in the bottom-right corner of every page, once it's scrolled down by one screen, on screens at least 768px wide. Scroll down to see this site's own.

Customized with component tokens

CSS
.customBackToTop {
  --component-back-to-top-offset: var(--space-layout-sm);
  --component-back-to-top-shadow: var(--effect-elevation-raised);
}

Props

Any native prop not listed here goes to the root element unchanged.

There are no children: the arrow and the label are built in. It's a library Button, so the native button props, className and ref reach the button, except disabled and aria-pressed. An onClick runs first; calling event.preventDefault() in it cancels the scroll and the focus move.

BackToTop props
PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost""secondary"Emphasis: one primary action per view, secondary for the rest, ghost for toolbars.
size"sm" | "md""md"32px or 40px tall.
labelstring"Back to top"The accessible name, and the visible text with showLabel.
showLabelbooleanfalseShows the label beside the arrow. Without it the button is icon-only and shows its name as a tooltip on hover and focus.
thresholdnumberthe viewport's heightHow far, in pixels, the page scrolls before the button appears. In the corner it only appears on viewports at least 48em (768px) wide; phones scroll to the top from the status bar.
visibleboolean—Overrides the automatic visibility: true always shows it, false always hides it. Hidden, it's out of the tab order and the accessibility tree.
placement"corner" | "inline""corner"corner is fixed at the viewport's bottom-right corner (bottom-left in right-to-left text), with a shadow. inline sits in the flow.
focusTarget() => HTMLElement | nullmain's h1, else mainWhere focus goes after scrolling. An element that can't take focus gets tabindex=-1 first.

Component tokens

BackToTop component tokens
TokenCopyDescriptionAliasesLightDarkPreview
--component-back-to-top-offsetDistance of the corner button from the viewport's block-end and inline-end edges.space.layout.xs1remfrom space.41remfrom space.4
--component-back-to-top-shiftHow far it slides in when it appears (none under reduced motion).space.stack.sm0.5remfrom space.20.5remfrom space.2
--component-back-to-top-shadowShadow of the corner button, so it reads above the page. The inline placement has none.effect.elevation.overlay0px 4px 12px 0px rgb(0% 0% 0% / 0.12)from effect.shadow.md0px 4px 12px 0px rgb(0% 0% 0% / 0.4)from effect.shadow.md-dark
--component-back-to-top-layerStacking order of the corner button: the same level as the sticky header.layer.sticky2from layer.22from layer.2No preview
--component-back-to-top-durationDuration of showing and hiding (0ms under reduced motion).motion.duration.base250msfrom motion.time.250Reduced motion: 0ms250msfrom motion.time.250No preview

Accessibility

  • A native button named "Back to top" (or its label). Icon-only, it shows that name as a tooltip on hover and keyboard focus; the arrow is decorative.
  • In the corner it only appears on viewports at least 48em (768px) wide: phones scroll to the top from the status bar, and on a small screen with large text the sticky header leaves no room to keep focused content clear of it.
  • Until the page is scrolled past the threshold it's hidden from sight, from the tab order and from the accessibility tree. Once shown, it stays while it has focus, so focus never drops to the page when it scrolls up under the button.
  • Activating it scrolls to the top and moves focus to the page's h1 (or main), without a second scroll, so the next Tab continues from the top of the page.
  • It scrolls smoothly only when the reader hasn't asked for reduced motion; otherwise it jumps. Showing and hiding fade and slide in, with no slide and no fade time under reduced motion.
  • While the corner button shows, the page keeps a scroll padding at its bottom as tall as the button and its offset, so it never covers a focused element (WCAG 2.4.11).
  • It has Button's focus ring, 40px target (32px when small), contrast and forced-colors look.
BackToTop keyboard
KeyAction
EnterScrolls to the top and moves focus to the page's heading.
SpaceScrolls to the top and moves focus to the page's heading.