Pull to Refresh

Refreshes a scrolling list when the user pulls it down.

Installation

pnpm dlx shadcn@latest add @paneui/pull-to-refresh

Usage

Examples

Labels and Distances

Use to match your app's wording or change how far the pull must go.

External Refreshing

Use when a refresh can also start elsewhere, like a Sync button, and should hold the spinner open.

Status Changes

Use to drive your own indicator from the gesture.

Disabled

Scrollbars

Scrolls in a Scroll Area, so its scrollbar stays inside the rounded frame and holds still while the content is pulled. The pull never changes the scroll range.

Motion

Content springs back once onRefresh resolves. With reduced motion it jumps into place and the arrow doesn't rotate.

Accessibility

The root sets aria-busy while refreshing and a polite live region announces refreshingLabel. Pull is a touch, pen and mouse gesture only, so give keyboard users another way to refresh.

API Reference

PullToRefresh

Scroll container that arms a refresh when pulled down from the top. Give it a height. Also accepts every prop of div.

children*
ReactNode
The scrolling content.
onRefresh*
() => void | Promise<void>
Runs when the pull is released past threshold. Return a promise to keep the spinner until it settles, or return nothing and set refreshing instead.
refreshing
boolean
Hold the refreshing state for a refresh managed outside the gesture. The content stays open until both this and any onRefresh promise are done.
disabled= false
boolean
Turn the pull gesture off.
threshold= 64
number
Resisted pull distance (px) that arms the refresh.
maxPull= 120
number
Ceiling of the resisted pull (px).
holdDistance= 56
number
Content offset (px) while refreshing.
pullingLabel= "Pull to refresh"
ReactNode
Shown while pulling, before the threshold.
releaseLabel= "Release to refresh"
ReactNode
Shown once the pull is armed.
refreshingLabel= "Refreshing…"
ReactNode
Shown and announced while refreshing.
onStatusChange
(status: "idle" | "pulling" | "ready" | "refreshing") => void
Called whenever the gesture status changes.
contentClassName
string
Classes for the content that moves with the pull.
PropTypeDefaultDescription
children*ReactNode—The scrolling content.
onRefresh*() => void | Promise<void>—Runs when the pull is released past threshold. Return a promise to keep the spinner until it settles, or return nothing and set refreshing instead.
refreshingboolean—Hold the refreshing state for a refresh managed outside the gesture. The content stays open until both this and any onRefresh promise are done.
disabledbooleanfalseTurn the pull gesture off.
thresholdnumber64Resisted pull distance (px) that arms the refresh.
maxPullnumber120Ceiling of the resisted pull (px).
holdDistancenumber56Content offset (px) while refreshing.
pullingLabelReactNode"Pull to refresh"Shown while pulling, before the threshold.
releaseLabelReactNode"Release to refresh"Shown once the pull is armed.
refreshingLabelReactNode"Refreshing…"Shown and announced while refreshing.
onStatusChange(status: "idle" | "pulling" | "ready" | "refreshing") => void—Called whenever the gesture status changes.
contentClassNamestring—Classes for the content that moves with the pull.
data-status
idle, pulling, ready or refreshing on the root.
Data attributeDescription
data-statusidle, pulling, ready or refreshing on the root.