---
title: useScrollShadow
description: Track whether a scroll container has hidden content past its start/end edges, so you can fade in shadows on the overflowing sides only.
icon: scroll-text
---

### Installation

```package-install
npx shadcn@latest add @redpanda/use-scroll-shadow
```

`useScrollShadow` watches a scroll container and reports whether content is hidden past its **start** and **end** edges. Use it to fade in edge shadows (or arrows) only on the sides that actually overflow. It re-reads scroll geometry on scroll and whenever the container or its children resize, and only re-renders when an edge actually flips — not on every scroll frame.

For `vertical` orientation, `start`/`end` map to top/bottom; for `horizontal`, to left/right.

:::info
Horizontal mode assumes **LTR** layout (`scrollLeft` grows from 0 at the start edge). RTL is not handled.
:::

## Usage

```tsx showLineNumbers
import { useRef } from "react";
import { useScrollShadow } from "@/hooks/use-scroll-shadow";
import { cn } from "@/lib/utils";

function ShadowedList() {
  const ref = useRef<HTMLDivElement>(null);
  const { start, end } = useScrollShadow(ref);

  return (
    <div className="relative">
      <div
        className={cn(
          "pointer-events-none absolute inset-x-0 top-0 h-4 bg-gradient-to-b from-background to-transparent transition-opacity",
          start ? "opacity-100" : "opacity-0"
        )}
      />
      <div ref={ref} className="max-h-64 overflow-y-auto">
        {/* long content */}
      </div>
      <div
        className={cn(
          "pointer-events-none absolute inset-x-0 bottom-0 h-4 bg-gradient-to-t from-background to-transparent transition-opacity",
          end ? "opacity-100" : "opacity-0"
        )}
      />
    </div>
  );
}
```

## API

### `useScrollShadow<T>(ref, enabled?, orientation?)`

| Parameter     | Type                            | Default      | Description                                                        |
| ------------- | ------------------------------- | ------------ | ------------------------------------------------------------------ |
| `ref`         | `RefObject<T \| null>`          | —            | Ref to the scroll container element.                               |
| `enabled`     | `boolean`                       | `true`       | When `false`, listeners are not attached and edges stay `false`.   |
| `orientation` | `'vertical' \| 'horizontal'`    | `'vertical'` | Axis to observe.                                                   |

**Returns** `{ start: boolean; end: boolean }` — whether content is hidden past the start/end edge.
