Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
On this page

useScrollShadow

Track whether a scroll container has hidden content past its start/end edges, so you can fade in shadows on the overflowing sides only.

Installation

npx shadcn@latest add @redpanda/use-scroll-shadow
pnpm dlx shadcn@latest add @redpanda/use-scroll-shadow
yarn dlx shadcn@latest add @redpanda/use-scroll-shadow
bunx shadcn@latest add @redpanda/use-scroll-shadow
nubx shadcn@latest add @redpanda/use-scroll-shadow
aube dlx 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.

Usage

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.

Last updated on October 7, 2026

Was this page helpful?