v1.0 · Stable

Back to top

A floating “scroll to top” button. It composes ng-btn for the whole look (color, shape, size); .ng-back-to-top only adds the fixed position, the show/hide on scroll, the scroll behavior and an optional progress ring. Zero dependencies.

Variants

Style it with any ng-btn classes. data-ng-back-to-top is the required marker.

icon-only.html
<button class="ng-back-to-top ng-btn ng-btn-primary circle" data-ng-back-to-top aria-label="Back to top">
    <i class="ph ph-arrow-up"></i>
</button>
text.html
<button class="ng-back-to-top ng-btn ng-btn-primary" data-ng-back-to-top>Top</button>
icon-text.html
<button class="ng-back-to-top ng-btn ng-btn-secondary" data-ng-back-to-top>
    <i class="ph ph-arrow-up"></i> <span>Back to top</span>
</button>

No own sizes: use ng-btn sizes — xs / sm / lg (default md).

Progress ring

Add data-ng-progress and a <span class="ng-back-to-top-ring">. The JS updates --ng-btt-progress (scroll %) each frame (same conic-gradient + mask as the donut chart). On a solid button set --ng-btt-ring-color to the brand (otherwise it inherits the white text color).

ring.html
<!-- progress ring (icon-only). On a SOLID button set the ring color to the brand -->
<button class="ng-back-to-top ng-btn ng-btn-primary circle" data-ng-back-to-top data-ng-progress
        style="--ng-btt-ring-color: var(--ng-primary-bg); --ng-btt-ring-track: rgba(0,0,0,.10)">
    <span class="ng-back-to-top-ring" aria-hidden="true"></span>
    <i class="ph ph-arrow-up"></i>
</button>

Container scope

To watch a scrollable element instead of the window, put the button outside the scroll element (as a sibling), in a position:relative wrapper, and add .contained + data-ng-scope.

scope.html
<!-- the button is a SIBLING of the scrollable box, inside a position:relative wrapper -->
<div style="position:relative">
    <div id="box" style="height:240px;overflow:auto">…tall content…</div>
    <button class="ng-back-to-top contained ng-btn ng-btn-info circle"
            data-ng-back-to-top data-ng-scope="#box" data-ng-target="#boxtop"
            style="--ng-btt-offset:12px"><i class="ph ph-arrow-up"></i></button>
</div>
Live preview (scroll the box)

Scrollable content line 1.

Scrollable content line 2.

Scrollable content line 3.

Scrollable content line 4.

Scrollable content line 5.

Scrollable content line 6.

Scrollable content line 7.

Scrollable content line 8.

Scrollable content line 9.

Scrollable content line 10.

Scrollable content line 11.

Scrollable content line 12.

Reference

Behavior options (data-ng-*)

data-ng-back-to-topMarker (required).
data-ng-thresholdShow after this scroll. Default 300 · px or % (e.g. 50%).
data-ng-behaviorsmooth (default) · instant (respects prefers-reduced-motion).
data-ng-targetSelector to scroll to (default: top 0).
data-ng-scopeScrollable container selector (default: window).
data-ng-progressEnables the ring (needs the ring span).
data-ng-auto-hideDefault false: true hides again near the bottom.
data-ng-offsetOverride corner offset (px).
data-ng-labelDefault “Back to top”: sets aria-label + title.

Class options

Corner:

.bottom-right.bottom-left.bottom-center.top-right.top-left.top-center

Animation / misc:

.fade.slide.scale.hide-on-mobile.contained

Events (detail { backToTop })

ng:back-to-top:showng:back-to-top:hideng:back-to-top:click

Instance API (el.__ngBackToTop)

.show().hide().scrollToTop().update()

Foot

index.html
<script type="module" src="/assets/js/ng_core.js"></script>
<!-- components… -->
<script type="module" src="/assets/js/ng_back_to_top.js"></script>
<script type="module" src="/assets/js/ng_observer.js"></script>