# Back to top

> A link that appears once a long page has scrolled down, and returns to the top with focus on the main content.

## Anatomy

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](/floating-action-button.html.md) 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.

[](#docs-main)

```
<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](/scroll-area.html.md) 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 |
