Sticky Scroll
A scroll container that auto-follows new content while the user is at the bottom, but holds its position the moment they scroll up to read history — chat logs, activity feeds, build output, terminals.
Basic Usage
Live activity feed
New rows stream in every 1.8s. While you are at the bottom the view auto-follows. Scroll up to read an older row and it stays put — a 'jump to latest' button appears so you can re-pin.
import { StickyScroll } from 'fluxo-ui';
<StickyScroll maxHeight={320}>
{messages.map((m) => (
<div key={m.id}>{m.text}</div>
))}
</StickyScroll>Labelled Button
Labelled jump button
Pass jumpButtonLabel to render a pill with text instead of the icon-only chevron. It only shows while the user has scrolled away from the bottom.
<StickyScroll maxHeight={300} jumpButtonLabel="Jump to latest">
{rows}
</StickyScroll>Imperative & State
Imperative handle & pinned state
Call scrollToBottom() via a ref, and observe pinned state through onPinnedChange. Useful for a custom 'send' button that always re-pins.
const ref = useRef<StickyScrollHandle>(null);
<StickyScroll ref={ref} maxHeight={300} onPinnedChange={setPinned}>
{rows}
</StickyScroll>
<Button label="Scroll to bottom" onClick={() => ref.current?.scrollToBottom()} />Import
import { StickyScroll } from 'fluxo-ui';
import type { StickyScrollProps, StickyScrollHandle, StickyScrollBehavior } from 'fluxo-ui';Props
childrenreqReactNodeScrollable content. New items appended at the end trigger auto-scroll when pinned
childrenreqReactNodeScrollable content. New items appended at the end trigger auto-scroll when pinned
thresholdnumber"48"Distance in px from the bottom within which the view is considered pinned
thresholdnumber"48"Distance in px from the bottom within which the view is considered pinned
initialPinnedboolean"true"Start scrolled to the bottom and pinned on mount
initialPinnedboolean"true"Start scrolled to the bottom and pinned on mount
behavior'smooth' | 'auto'"'smooth'"Scroll behavior for the jump button; auto-falls back under prefers-reduced-motion
behavior'smooth' | 'auto'"'smooth'"Scroll behavior for the jump button; auto-falls back under prefers-reduced-motion
showJumpButtonboolean"true"Show a 'jump to latest' button while the user is scrolled up
showJumpButtonboolean"true"Show a 'jump to latest' button while the user is scrolled up
jumpButtonLabelstringOptional visible text on the jump button (icon-only when omitted)
jumpButtonLabelstringOptional visible text on the jump button (icon-only when omitted)
maxHeightnumber | stringMax height of the scroll viewport (number is px)
maxHeightnumber | stringMax height of the scroll viewport (number is px)
heightnumber | stringFixed height of the scroll viewport (number is px)
heightnumber | stringFixed height of the scroll viewport (number is px)
onPinnedChange(pinned: boolean) => voidFires when the pinned-to-bottom state changes
onPinnedChange(pinned: boolean) => voidFires when the pinned-to-bottom state changes
classNamestringAdditional CSS classes on the outer wrapper
classNamestringAdditional CSS classes on the outer wrapper
contentClassNamestringAdditional CSS classes on the inner content element
contentClassNamestringAdditional CSS classes on the inner content element
idstringHTML id attribute on the scroll viewport
idstringHTML id attribute on the scroll viewport
ariaLabelstringAccessible label for the scroll viewport
ariaLabelstringAccessible label for the scroll viewport
rolestringARIA role for the scroll viewport (e.g. 'log' for live activity feeds)
rolestringARIA role for the scroll viewport (e.g. 'log' for live activity feeds)
Features
Smart Auto-Follow
Appends auto-scroll the view only while the user is already at the bottom — never yanks them back when reading older content.
Jump To Latest
A floating button appears the moment the user scrolls up, letting them re-pin to the newest content with one click.
Resize-Aware
A ResizeObserver keeps the view pinned even when items grow in height, not just when new ones are added.
Imperative Handle
scrollToBottom(), isPinned(), and getElement() via ref for custom controls and integrations.
Reduced Motion
Falls back to instant scroll under prefers-reduced-motion and dampens the button animation.
Accessible
Keyboard-focusable jump button with aria-label, an aria-hidden state when pinned, and an optional role like log for live regions.