# useStickToBottom

Keeps a scrollable element scrolled to the bottom as content is added or grows, like a chat or a log, until the user scrolls up to read. Scrolling back to the bottom, or calling `scrollToBottom`, follows again.

Follows content that grows with no scroll event, such as an AI reply streamed into the last message. Starts at the bottom. Only scrolling up stops following (wheel, touch, keys, or scrollbar), and it stops as soon as the user starts, so it never cancels their scroll. Its own scrolling never counts as the user's.

## Import

```ts
import { useStickToBottom } from '@vincent.ri/react-tils'
// or only this hook
import { useStickToBottom } from '@vincent.ri/react-tils/useStickToBottom'
```

## Usage

```ts
const [ref, { atBottom, scrollToBottom }] = useStickToBottom<HTMLDivElement>()
return (
  <>
    <div ref={ref} style={{ overflowY: 'auto', height: 500 }}>
      {messages.map((m) => <Message key={m.id} {...m} />)}
    </div>
    {!atBottom && <button onClick={() => scrollToBottom()}>Jump to latest</button>}
  </>
)
```

## When to use it

A chat, AI chat, terminal output, or live log.

## When not to

New items appear at the top (a feed). Loading older messages above doesn't need it either, but Safari has no scroll anchoring, so there the view jumps unless you restore the position yourself: after prepending, add the change in `scrollHeight` to `scrollTop`. For only reading the scroll position, use `useElementScroll`.

## API

```ts
function useStickToBottom<T extends HTMLElement = HTMLElement>(): [(element: T | null) => void, StickToBottom]
```

**Returns** `[ref, { atBottom, scrollToBottom }]`. Pass `ref` to the scrollable element (with `overflow: auto` and a fixed or max height).

### Types

```ts
export type StickToBottom = {
  /** Following new content. `false` after the user scrolls up; `true` again at the bottom. */
  atBottom: boolean;
  /** Scroll to the bottom and follow new content again. Default behavior `'smooth'`. */
  scrollToBottom: (behavior?: ScrollBehavior) => void;
};
```

## Browser support

Works in all modern browsers.

## Coming from another library?

Other libraries call this `useAutoScroll`, `useChatScroll`.

---

589 B minified and brotlied
Source: https://github.com/vincentri/react-tils/blob/main/src/useStickToBottom.ts
Docs page: https://vincentri.github.io/react-tils/hooks/useStickToBottom/
Previous: [useIsStuck](https://vincentri.github.io/react-tils/hooks/useIsStuck.md)
Next: [useMergedRefs](https://vincentri.github.io/react-tils/hooks/useMergedRefs.md)
