Back to Top
Floating button that appears once the page is scrolled past a threshold and smooth-scrolls back to the top on click.
Try it
The element is mounted on this page. Scroll down past ~300px and a button appears pinned to the bottom-right corner — click it to smooth-scroll back up.
<esa-back-to-top></esa-back-to-top>
API
Attributes and properties:
| Prop | Type | Default | Description |
|---|---|---|---|
threshold | number | 300 | Scroll distance (px) before the button fades in. |
smooth-scroll | boolean | true | Smooth vs instant scroll-to-top. (Property: smoothScroll.) Property: `smoothScroll`. On by default. Write `="false"` to turn it off — unusually for a boolean attribute, this one reads the value. |
scrollTarget | HTMLElement | null | null | JS-only property — element to track instead of window. Set as a JS property — there is no attribute. |
visible | boolean | false | Reflected attribute set when scrolled past the threshold; drives the fade/translate. |
No custom events — clicking the button scrolls the target (or window) to the top directly.
Accessibility
- Renders a native
<button>witharia-label="Back to top". - While hidden it is
pointer-events: nonewithopacity: 0, so it isn't a click target until visible. - Visible focus ring via the
--focus-ring-*tokens; the chevron icon isaria-hidden.
Theming surface
Every public token this component reads, extracted from its source at build time,
split by blast radius: the hooks that belong to this component,
then the shared and system tokens it consumes alongside everything else. The
Resolves to column walks each token's real lineage —
component → semantic → primitive → raw value — so you
can see exactly where re-pointing it lands. A spoke re-skins by overriding these in
its theme-<slug>.css; component internals are never edited. No
hook for what you need? File it with /request-lego.
Wired to this component
No other component reads these — re-point them and esa-back-to-top is the
only thing that moves.
| Token | Tier | Resolves to |
|---|---|---|
--back-to-top-size | component | 44px |
Shared tokens it reads
Owned by a family or by the semantic layer. Still overridable — but scope the
override (esa-foo { --form-border-color: … }) unless you mean to move
everything that reads it. Reach says what else that is.
| Token | Reach | Resolves to |
|---|---|---|
--focus-ring-color | component focus ring group · +34 more | #3e9b4f via --color-border-default-focus → --color-grass-10 |
--focus-ring-offset | component focus ring group · +31 more | 2px |
--focus-ring-width | component focus ring group · +35 more | 2px via --border-width-focus → --border-width-200 |
--color-background-brand | semantic every component | #46a758 via --color-grass-9 |
--color-background-brand-hover | semantic every component | #3e9b4f via --color-grass-10 |
--color-content-default-knockout | semantic every component | #fcfcfc via --color-gray-1 |
--elevation-3 | semantic every component | 0 via --shadow-offset-x |
--elevation-4 | semantic every component | 0 via --shadow-offset-x |
--radius-pill | semantic every component | 9999px via --radius-full |
--transition-base | semantic every component | 200ms via --duration-200 |
--transition-fast | semantic every component | 150ms via --duration-150 |
--z-sidebar | semantic every component | 100 |
--spacing-500 | primitive every component | 1.5rem |