useStickToBottom
Designed with AI chat bots in mind
If you or your company finds this hook useful Sponsor me on GitHub
A lightweight zero-dependency React hook + Component that automatically sticks to the bottom of container and smoothly animates the content to keep it's visual position on screen whilst new content is being added.
Features
- Does not require
overflow-anchorbrowser-level CSS support which Safari does not support. - Can be connected up to any existing component using a hook with refs. Or simply use the provided component, which handles the refs for you plus provides context - so child components can check
isAtBottom& programmatically scroll to the bottom. - Uses the modern, yet well-supported,
ResizeObserverAPI to detect when content resizes.- Supports content shrinking without losing stickiness - not just getting taller.
- Correctly handles Scroll Anchoring. This is where when content above the viewport resizes, it doesn't cause the content currently displayed in viewport to jump up or down.
- Allows the user to cancel the stickiness at any time by scrolling up.
- Clever logic distinguishes the user scrolling from the custom animation scroll events (without doing any debouncing which could cause some events to be missed).
- Mobile devices work well with this logic too.
- Uses a custom implemented smooth scrolling algorithm, featuring velocity-based spring animations (with configurable parameters).
- Other libraries use easing functions with durations instead, but these doesn't work well when you want to stream in new content with variable sizing - which is common for AI chatbot use cases.
scrollToBottomreturns aPromisewhich will resolve totrueas soon as the scroll was successful, orfalseif the scroll was cancelled.
Installation
npm install use-stick-to-bottom
Usage
`` Component
import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom';
function Chat() {
return (
{messages.map((message) => (
))}
{/* This component uses `useStickToBottomContext` to scroll to bottom when the user enters a message */}
);
}
function ScrollToBottom() {
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
return (
!isAtBottom && (
scrollToBottom()}
/>
)
);
}
useStickToBottom Hook
import { useStickToBottom } from 'use-stick-to-bottom';
function Component() {
const { scrollRef, contentRef } = useStickToBottom();
return (
{messages.map((message) => (
))}
);
}