Skip to content
kitn AI/UI

Scroll Button

kai-scroll-button

Appears once the reader scrolls up, so the latest message is a click away.

  • Shadow DOM
  • 1 event
  • 3 button variants
  • Auto-hides at bottom
  • Works via id or ancestor walk

Point the button at its scroll container with the for attribute:

<div id="my-feed" style="height:400px; overflow-y:auto; position:relative;">
<!-- list content -->
</div>
<kai-scroll-button for="my-feed"></kai-scroll-button>
<script type="module">
import '@kitn.ai/ui/web-components';
</script>
  • for — the id of the scrollable container (mirrors <label for="...">). Omit to walk up the composed tree to the nearest scrollable ancestor.
  • Visibility — hidden when the container is within 50 px of the bottom; animated (translate + scale + opacity) otherwise. Uses a passive scroll listener — no polling.
  • kai-scroll — fires (no detail) each time the button is clicked and scrollToBottom() completes. Use it to pause auto-scroll logic.

No placement prop, and no positioning CSS of its own: floating the button over the thread is three lines of your layout.

  1. Put position: relative on a box that does not scroll, wrapping the scroll container. Not on the scroll container itself: an absolutely positioned child of a scrolling element is placed against its padding box and then scrolls away with the content.
  2. Give the button position: absolute and an offset from the bottom.
  3. Centre it, or anchor it to a corner.
<!-- the WRAPPER is the positioning context, not the scroll container -->
<div style="position:relative; height:400px">
<div id="my-feed" style="height:100%; overflow-y:auto"><!-- messages --></div>
<!-- centred over the content -->
<kai-scroll-button for="my-feed"
style="position:absolute; left:50%; bottom:12px; transform:translateX(-50%)">
</kai-scroll-button>
<!-- or anchored to the corner -->
<kai-scroll-button for="my-feed"
style="position:absolute; right:12px; bottom:12px">
</kai-scroll-button>
</div>

On a wide thread, centre on the message column rather than the container, the way <kai-chat> does internally: the wrapper takes the same max width as the messages and is centred with left:50% plus translateX(-50%).

When a composer is docked at the bottom, raise the offset so the button clears it (bottom:56px suits a typical one).

label sets the accessible name, announced whether or not the button is visible, and defaults to Scroll to bottom.

show-label also draws that text beside the icon, so the visible text is the accessible name and nothing gets announced twice.

<!-- icon only, announced in German -->
<kai-scroll-button for="my-feed" label="Zum Ende springen"></kai-scroll-button>
<!-- the name drawn beside the icon -->
<kai-scroll-button for="my-feed" show-label label="Jump to latest"></kai-scroll-button>

Scroll the list up to reveal it, click to jump back.

PropertyTypeDefaultNotes
theme'auto'Color mode (`auto` follows prefers-color-scheme).
for—CSS id of the scroll container to control.
variant'outline'Button visual variant. Defaults to `outline`.
size'icon'Button size token. Defaults to `'icon'` (square).
label—The button's accessible name. It is announced whether or not the label is visible, so the text is always localisable. Defaults to `'Scroll to bottom'`.
showLabel—Also render `label` visibly beside the icon. Default `false` (icon-only).
EventDetailNotes
— Emitted when the user clicks the button and `scrollToBottom()` is called. Carries no detail; consumers use it to know a manual scroll occurred.

This element wraps these SolidJS components — reach for them directly when you need finer control than the props expose.

Button