# useScrollState

> A React scroll position hook: offset, progress and hide-on-scroll state for the window or a container, as motion values without re-renders.

- Type: React hook (Hooks & Utilities)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add use-scroll-state`
- Docs: https://wingo-ui.com/components/use-scroll-state

## Interaction

Scroll the feed in the phone frame: the top bar slides away with your finger as you scroll down and comes back the moment you scroll up, then settles fully shown or hidden when you stop. The progress line under it fills as you read, the large title fades into the bar, and a back-to-top button appears once you pass the threshold. The readout shows direction, scrolled and hidden flipping without a render per frame.

## Installation

```bash
npx wingo-ui@latest add use-scroll-state
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/use-scroll-state` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `hooks/use-scroll-state.ts`

npm dependencies: `npm i motion`

Wingo UI dependencies (installed automatically):

- [useMediaQuery](https://wingo-ui.com/components/use-media-query) ([Markdown](https://wingo-ui.com/components/use-media-query.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))

## Usage

```tsx
import { motion, useTransform } from "motion/react"
import { useScrollState } from "@/hooks/use-scroll-state"
import { cn } from "@/lib/utils"

export function AppHeader() {
  const { hideProgress, scrolled } = useScrollState({ hideOnScroll: true, hideDistance: 56 })
  const y = useTransform(hideProgress, [0, 1], [0, -56])

  return (
    <motion.header
      style={{ y }}
      className={cn(
        "sticky top-0 z-sticky flex h-14 items-center bg-background/80 px-4 backdrop-blur-xl",
        scrolled && "border-b border-foreground/10",
      )}
    >
      <h1 className="text-[17px] font-semibold">Listings in New York</h1>
    </motion.header>
  )
}
```

## API

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `hideOnScroll?` | `boolean` | `false` | useScrollState(options?): track hideProgress and hidden for a bar that slides away while you scroll down. Off by default, so hooks that only read the offset do no extra work. |
| `hideDistance?` | `number` | `56` | Pixels of scrolling that take a bar from shown to hidden, usually the bar's own height, so it moves 1:1 with the content. |
| `hideOffset?` | `number` | `0` | The bar never hides above this offset, e.g. while a page header is still on screen. It can always come back. |
| `snap?` | `boolean` | `true` | After scrolling stops, a half-hidden bar settles to shown or hidden on the snappy spring. |
| `revealAtEnd?` | `boolean` | `true` | Bring the bar back at the very end of the content, where nothing is left to uncover. |
| `scrolledThreshold?` | `number` | `1` | scrolled turns true past this many pixels: 1 for a header hairline, 400 for a back-to-top button. |
| `target?` | `HTMLElement \| Window \| RefObject<HTMLElement \| null> \| null` |  | What to watch. Default: the nearest ScrollContainerProvider, else the window. A ref is read after mount; pass the element itself when it can change. |
| `disabled?` | `boolean` | `false` | Stops listening; the values keep their last state. |
| `returns?` | `{ offset: MotionValue<number>; progress: MotionValue<number>; hideProgress: MotionValue<number>; direction: "up" \| "down" \| null; scrolled: boolean; hidden: boolean; atEnd: boolean; scrollTo(top, { smooth? }): void }` |  | offset (px, negative during an iOS bounce), progress (0 to 1) and hideProgress (0 shown to 1 hidden, following the finger) are motion values: feed them to useTransform and style. direction, scrolled, hidden and atEnd re-render only when they flip. scrollTo is smooth unless the user prefers reduced motion; under reduced motion hideProgress only ever jumps between 0 and 1. |

## Parts

### ScrollContainerProvider (component)

Declares the element that scrolls for everything inside it (an app shell's content area, a demo box, a phone frame). Keep the element in state through a callback ref so the children update once it mounts. Props: ({ value: HTMLElement | null; children }) => JSX.Element.

### useScrollContainer (hook)

The nearest provided scroll container, or null for the window. Scroll spies use it as their IntersectionObserver root. Signature: () => HTMLElement | null.

### findScrollParent (function)

The nearest vertically scrolling ancestor of an element, or null for the window. Signature: (element) => HTMLElement | null.

### scrollToOffset (function)

Scrolls an element or the window to an offset outside React, instant under reduced motion. Signature: (target, top, smooth?) => void.

### ScrollContainerProviderProps (type)

{ value: HTMLElement | null; children?: ReactNode }.

### ScrollTarget (type)

What target accepts: HTMLElement | Window | RefObject<HTMLElement | null> | null | undefined.

### ScrollDirection (type)

"up" | "down", the last scroll direction.

### UseScrollStateOptions (type)

The options object: target, scrolledThreshold, hideOnScroll, hideDistance, hideOffset, revealAtEnd, snap and disabled.

### ScrollState (type)

The return value: offset, progress and hideProgress motion values, the direction, scrolled, hidden and atEnd flags, and scrollTo.

## Examples

- **Reading progress**: A bar that fills as you read an article in its own scroll container, through the target option.
- **Bottom actions that step aside**: hideOnScroll slides the action bar down while you scroll the list and brings it back on the way up.

## See also

- [Scroll Progress](https://wingo-ui.com/components/scroll-progress) ([Markdown](https://wingo-ui.com/components/scroll-progress.md))
- [Back To Top](https://wingo-ui.com/components/back-to-top) ([Markdown](https://wingo-ui.com/components/back-to-top.md))
- [useScrollEdges](https://wingo-ui.com/components/use-scroll-edges) ([Markdown](https://wingo-ui.com/components/use-scroll-edges.md))
- [Large Title Header](https://wingo-ui.com/components/large-title-header) ([Markdown](https://wingo-ui.com/components/large-title-header.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))

---

Canonical: https://wingo-ui.com/components/use-scroll-state
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
