Use .back-to-top for a link that appears once a long page has
scrolled down, and takes the reader back to the top.
Write an <a> whose href names the page's main
content, give it an aria-label, and add the
FAB classes
button circle extra for its look. AutoInit() starts
every .back-to-top. The link stays hidden until the page has
scrolled one viewport height, then sits in the bottom inline-end corner.
Activating it scrolls to the top and moves focus to the element the
href names. Scroll this page down to see the one below.
<main id="main">…</main>
<a class="back-to-top button circle extra" href="#main" aria-label="Back to top">
<span class="material-symbols" aria-hidden="true">arrow_upward</span>
</a>
Without the script, the link is always visible and jumps to its target,
as any in-page link does. Until the script starts it is also visible at
the top of the page, so call AutoInit() before the first
paint, from a script at the end of the body.
Where focus goes
Focus moves to the href target, so the next Tab reaches the
first control after it. A target that does not take focus, such as a
<main>, gets tabindex="-1" until it loses focus
again. An href of # or #top, or one that
names no element, focuses the body instead. The address bar keeps its
fragment, since the script replaces the jump. A click with Ctrl, Meta,
Shift or Alt, or one a page handler already prevented, is left to the
browser.
While hidden, the link is inert: Tab skips it, it takes no
clicks, and screen readers do not list it. That state belongs to the
script, so don't write inert in the markup. A focused link
stays until focus leaves, so pressing Home on it does not drop focus
to the body.
What scrolls
The link watches the window's scroll, through an
IntersectionObserver on an empty element at the threshold, so
scrolling runs no script. The threshold is measured from the top of the
body, so a body with position: relative adds its own top margin.
A pane, dialog or scroll area that scrolls
on its own is not supported.
The scroll to the top is smooth, and instant under reduced motion. The link fades in and hides at once, and under reduced motion it also appears at once.
Options
| Name | Type | Default | Description |
|---|---|---|---|
threshold |
String | '100vh' |
How far the page scrolls before the link shows, as a CSS length from the top of the page. Viewport units follow window resizes. A value that is not a CSS length falls back to '100vh' with a warning. |
<a class="back-to-top button circle extra" href="#main" aria-label="Back to top"
data-back-to-top-options='{"threshold": "400px"}'>…</a>
Methods
const link = Expressive.BackToTop.getInstance(document.querySelector('.back-to-top'));
link.destroy(); // removes the observer and the threshold element, and shows the link again
Tokens
Override these on the .back-to-top. A .fab-menu sits
in the same corner, so a page with both raises one of them, for example with
--md-comp-back-to-top-offset: 88px.
| Token | Default |
|---|---|
--md-comp-back-to-top-offset | 16px |
--md-comp-back-to-top-z | 997 |
--md-comp-back-to-top-duration | the fast effects spring's duration |
--md-comp-back-to-top-easing | fast effects spring |