Xzero UI
Pro library

Stretch refreshPro

Pull a feed down and a line stretches to tell you when to let go.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/stretch-refresh
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/stretch-refresh

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { StretchRefresh } from "@/components/xzero/stretch-refresh/stretch-refresh";

export function Inbox() {
  const [messages, setMessages] = useState(initial);
  return (
    <StretchRefresh
      title="Inbox"
      items={messages}
      getKey={m => m.id}
      renderItem={m => <MessageRow message={m} />}
      onRefresh={async () => {
        const fresh = await fetchNew();
        setMessages(prev => [...fresh, ...prev]);
        return `${fresh.length} new messages`;
      }}
    />
  );
}

Examples

Fill the height of a sidebar

<aside style={{ display: "flex", flexDirection: "column", height: "100dvh" }}>
  <StretchRefresh
    title="Activity"
    items={events}
    getKey={e => e.id}
    renderItem={e => <EventRow event={e} />}
    onRefresh={reload}
    className="grow"
  />
</aside>

API reference

StretchRefresh

A feed that refreshes when pulled down past its top edge. The sheet rubber-bands while rows spread apart, a line in the gap stretches to show when to let go, then runs while the work happens.

PropTypeDefaultDescription
title (required)string–Heading above the feed.
subtitlestring–Short status under the heading, such as "Updated 14 min ago". A change rises in.
items (required)readonly T[]–Rows in the feed.
getKey (required)(item: T) => string–Stable key for each row.
renderItem (required)(item: T) => ReactNode–Renders one row.
onRefresh (required)() => Promise<string | void>–Runs after a pull past the threshold or a press of the refresh button. Update items before it resolves; resolve with a short result such as "3 new updates".
thresholdnumber72Pull distance in px, after resistance, that arms a refresh.
doneLabelstring"Up to date"Result shown when onRefresh resolves without one.
errorLabelstring"Couldn’t refresh"Result shown when onRefresh rejects.
refreshLabelstring"Refresh"Accessible name of the refresh button.
classNamestring–Extra class on the root.

Keyboard interactions

KeysAction
Enter / SpaceOn the refresh button, runs a refresh without pulling.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in loaders

Guidance for AI tools

Stretch refresh: Pull a feed down and a line stretches to tell you when to let go. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components