Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelog
    1. Startseite
    2. Blog
    3. Mobile UI mit React
    4. React Pull to Refresh in einer PWA ohne Browser-Ärger
    Read in English
    1. Blog
    2. Mobile UI mit React
    3. React Pull to Refresh in einer PWA ohne Browser-Ärger
    Mobile UI mit React
    Mobile UI mit React

    React Pull to Refresh in einer PWA ohne Browser-Ärger

    SR
    Serban Rusu · Gründer von Wingo UI
    9. Okt. 2026 · 11 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Warum braucht eine PWA ihr eigenes Pull to Refresh?
    2. Wie deaktivierst du das Pull to Refresh des Browsers?
    3. Wie viel Widerstand sollte ein Pull to Refresh haben?
    4. Pfeil, iOS-Speichen oder Material-Ring: Welcher Indikator passt?
    5. Wie fügst du Pull to Refresh einen haptischen Tick hinzu?
    6. Wie machst du ein eigenes Pull to Refresh barrierefrei?
    7. Wie nutzt du Pull to Refresh mit einer langen virtualisierten Liste?
    8. Welche Pull-to-Refresh-Fallen tauchen in Produktion auf?
    9. Was installierst du als Nächstes?
    10. Häufige Fragen
      1. Wie kann ich Pull to Refresh in Chrome deaktivieren?
      2. Stoppt overscroll-behavior Pull to Refresh in Safari auf iOS?
      3. Warum funktioniert preventDefault in onTouchMove in React nicht?
      4. Ist ein eigenes Pull to Refresh barrierefrei?
      5. Ist Pull To Refresh von Wingo UI kostenlos?

    Kurz gesagt

    Ein React Pull to Refresh, das in einer PWA zuverlässig funktioniert, braucht vier Dinge: overscroll-behavior-y: contain auf dem Scroller, damit Chrome die Seite nicht neu lädt, einen touchmove-Listener mit { passive: false }, weil Reacts onTouchMove passiv ist und Safari auf iOS overscroll-behavior für sein eigenes Refresh ignoriert, eine Gummiband-Kurve statt eines linearen Ziehwegs und einen Refresh-Button für alle, die nicht ziehen können. Wähl einen Indikator, der zur Plattform passt (iOS-Speichen, die die Liste nach unten schieben, oder einen Material-Ring, der darüber schwebt), und lös an der Schwelle einen haptischen Tick aus, als Extra und nie als einziges Signal. Pull To Refresh aus Wingo UI Pro erledigt all das in einer einzigen Komponente.

    Veröffentlicht am 9. Okt. 2026

    Ein React Pull to Refresh sieht nach vierzig Zeilen Touch-Handlern aus, bis es in einem Handy-Browser läuft. Chrome auf Android und Safari auf iOS haben ihr eigenes Pull to Refresh, das die Seite neu lädt. React registriert onTouchMove als passiv, also bewirkt preventDefault() nichts. Und eine Liste, die dem Finger eins zu eins folgt, fühlt sich auf dem Handy falsch an. Dieser Guide löst jedes dieser Probleme für eine PWA, mit dem nackten Muster und mit Pull To Refresh von Wingo UI, das alles in eine Komponente packt.

    Warum braucht eine PWA ihr eigenes Pull to Refresh?

    Weil die eingebaute Variante des Browsers das ganze Dokument neu lädt und es sie in der installierten App womöglich gar nicht gibt. Ein Reload führt jedes Skript neu aus und verwirft den gesamten Zustand im Speicher: geladene Daten, ein offenes Sheet, die Scrollposition einer verschachtelten Liste. Ein Daten-Refresh lädt nur die Liste neu. Und eine Web-App, die auf dem iPhone zum Home-Bildschirm hinzugefügt wurde, öffnet im Standalone-Modus, ohne Safaris Toolbar und ohne sein Pull to Refresh (wie Nutzer sie dort ablegen, zeigt unser Tutorial zum React PWA Install Prompt). Discourse hat eine Theme-Komponente veröffentlicht, um es zurückzubringen; die Ankündigung vom Dezember 2024 (opens in a new tab) beginnt mit der Feststellung, dass fehlendes Pull to Refresh eine große Lücke in iOS-PWAs ist.

    Fertige Pakete sind dünn gesät. Stand Oktober 2026 zeigt eine Suche nach pull to refresh react pwa noch immer @patlux/react-pull-to-refresh (opens in a new tab) (zuletzt veröffentlicht im November 2018) und react-js-pull-to-refresh (opens in a new tab) (zuletzt veröffentlicht im August 2022) weit oben, neben React-Native-Paketen, die nicht im Browser laufen. Android nennt die Geste Swipe to Refresh, React Swipe to Refresh ist also dasselbe unter anderem Namen.

    Wie deaktivierst du das Pull to Refresh des Browsers?

    Wer Pull to Refresh deaktivieren will, setzt overscroll-behavior-y: contain auf das Element, das scrollt: html, wenn das Fenster scrollt, sonst den Container. In Chrome erledigt diese eine Zeile das Thema overscroll-behavior Pull to Refresh komplett; dort gibt es die Eigenschaft seit Chrome 63 (opens in a new tab). contain behält den Overscroll-Glow, none entfernt ihn ebenfalls. Laut MDN (opens in a new tab) schaltet contain die native Navigation des Browsers ab, auch die vertikale Geste zum Aktualisieren.

    Safari ist die Ausnahme. Es unterstützt die Eigenschaft seit Safari 16 (caniuse (opens in a new tab)), aber WebKit-Bug 275947 (opens in a new tab), gemeldet im Juni 2024 und bei unserer Prüfung im Oktober 2026 noch offen, berichtet, dass weder none noch contain Safaris Pull to Refresh auf iOS deaktivieren. Dort hilft JavaScript: Sobald ein Finger, der ganz oben aufsetzt, nach unten wandert, ruf preventDefault() auf ihrem touchmove auf. Dann scrollt die Seite nicht, federt nicht und startet unter dem Finger kein Safari-Refresh.

    Genau hier kommt React in die Quere. Das Changelog von React 17 (opens in a new tab) hält fest, dass onTouchStart, onTouchMove und onWheel passiv bleiben. Ein passiver Listener kann das Event nicht abbrechen, also wird onTouchMove={(e) => e.preventDefault()} stillschweigend ignoriert. Häng den Listener selbst an, und zwar an den Scroller:

    ts
    // React registriert onTouchMove als passiven Listener, also wird preventDefault() darin ignoriert.
    // häng ihn selbst an den Scroller (auf document würde jeder Scroll der Seite auf diesen Handler warten)
    export function attachPull(scroller: HTMLElement, onPull: (dy: number) => void, onRelease: () => void) {
    let startY: number | null = null;
    let pulling = false;
    const start = (event: TouchEvent) => {
    pulling = false;
    startY = event.touches.length === 1 && scroller.scrollTop <= 0 ? event.touches[0].clientY : null;
    };
    const move = (event: TouchEvent) => {
    if (startY === null) return;
    const dy = event.touches[0].clientY - startY;
    if (!pulling && dy < 0) {
    // der Finger ging zuerst nach oben: ein normaler Scroll, überlass ihn dem Browser
    startY = null;
    return;
    }
    pulling = true;
    event.preventDefault(); // erlaubt, weil der Listener nicht passiv ist
    onPull(Math.max(0, dy));
    };
    const end = () => {
    if (pulling) onRelease();
    startY = null;
    pulling = false;
    };
    const previous = scroller.style.overscrollBehaviorY;
    scroller.style.overscrollBehaviorY = "contain";
    scroller.addEventListener("touchstart", start, { passive: true });
    scroller.addEventListener("touchmove", move, { passive: false });
    scroller.addEventListener("touchend", end);
    scroller.addEventListener("touchcancel", end);
    return () => {
    scroller.style.overscrollBehaviorY = previous;
    scroller.removeEventListener("touchstart", start);
    scroller.removeEventListener("touchmove", move);
    scroller.removeEventListener("touchend", end);
    scroller.removeEventListener("touchcancel", end);
    };
    }

    Ruf die Funktion in einem useEffect auf und gib ihr Cleanup zurück. Schreib dy in einen Motion Value oder eine Ref, nicht in State, sonst rendert jedes touchmove die Liste neu. Das ist ein Gerüst. Die Komponente von Wingo UI ergänzt, was fehlt: Sie wartet 8px Fingerweg ab, bevor sie entscheidet, ob eine Berührung ein Pull ist, verwirft Gesten, die eher seitwärts als nach unten gehen, bricht bei einem zweiten Finger ab (ein Pinch ist nie ein Pull) und startet nie in einem Eingabefeld, in [data-no-pull], in einem horizontalen Scroller oder in einer verschachtelten Liste, die selbst nicht ganz oben steht.

    Wie viel Widerstand sollte ein Pull to Refresh haben?

    Einen Widerstand, der wächst, je weiter der Finger geht. So bremst die Liste sanft ab, statt dem Finger eins zu eins bis zu einem harten Stopp zu folgen. react-simple-pull-to-refresh (opens in a new tab), das jüngste Web-Paket, das wir uns angesehen haben (1.3.4, 5. Januar 2026, MIT, React 16.10 bis 19), teilt den Fingerweg durch einen resistance-Prop (Standard 1) und begrenzt ihn bei maxPullDownDistance (Standard 95px): linear bis an eine Wand. Da es keine Abhängigkeiten hat, ist es eine solide Wahl für einen Prototyp.

    Eine native Liste folgt einer Kurve. Der Helper rubberband in lib/motion von Wingo UI nutzt eine im Stil von iOS, (1 - 1 / (x * 0.55 / d + 1)) * d. Dabei ist x der Fingerweg nach den 8px Toleranz und d die Höhe des Scrollers (mindestens 480px, damit eine kurze Box so viel Widerstand bietet wie eine in Handygröße). Auf einem Scroller mit 480px und den Standardwerten bewegen 100px Fingerweg die Liste um 49px und 200px um 89px. Der Refresh wird bei 72px (threshold) nach etwa 154px scharf, und die Liste geht nie über maxPull (128px) hinaus. Der Pull-Weg steckt in einem Motion Value, also rendert ein touchmove deine Liste nie neu; React-State ändert sich nur, wenn die Phase wechselt (pulling, armed, refreshing, done).

    Lässt du vor der Schwelle los, federt die Liste mit der Geschwindigkeit des Fingers zurück. Lässt du danach los, parkt sie an der Schwelle, während onRefresh läuft (mindestens 500ms, damit der Spinner nie nur aufblitzt). Danach zeigt sie für doneDuration (600ms) einen Haken, oder ein Warnsymbol, wenn das Promise fehlschlägt, bevor die Liste zurückgleitet. Bei reduzierter Bewegung springt die Liste zu jedem Ruhepunkt, statt zu federn.

    Pfeil, iOS-Speichen oder Material-Ring: Welcher Indikator passt?

    Richte dich nach der Plattform, die die meisten deiner Nutzer in der Hand halten, und entscheide, ob sich der Inhalt bewegen soll. Die drei Varianten der Komponente:

    variantDie ListeBeim ZiehenBeim AktualisierenPasst zu
    arrow (Standard)rutscht nach untenein Pfeil, der sich an der Schwelle drehtein Spinnerneutralen Apps auf beiden Plattformen
    iosrutscht nach unten12 Speichen, die nacheinander erscheinendie Speichen drehen sich in 12 Schritten, wie UIRefreshControlApps, die zuerst fürs iPhone gebaut sind
    materialbleibt stehenein schwebender Kreis, dessen Ring sich fülltein drehender Ring im KreisApps, die zuerst für Android gebaut sind, Bildraster, virtuelle Listen

    size setzt das Symbol auf 20, 24 oder 28px (den Material-Kreis auf 36, 40 oder 44px), tone färbt es (standardmäßig neutral), und showLabel ergänzt eine Zeile, die Pull to refresh, Release to refresh, Refreshing… und dann Updated anzeigt. Bei reduzierter Bewegung drehen sich die Speichen halb so schnell.

    Zieh den Posteingang mit dem Finger nach unten oder scroll auf dem Trackpad über den Anfang hinaus: Die Speichen erscheinen beim Ziehen, an der Schwelle wechselt das Label zu Release to refresh, und neue Nachrichten landen oben.
    $ npx wingo-ui@latest add pull-to-refresh
    ProDoku: Pull To Refresh

    Hier ein kompletter Posteingang, bei dem die iOS-Variante die List umschließt. scroll="self" macht die Komponente selbst zum Scroll-Container, mit overscroll-behavior-y: contain auf sich selbst. Mit dem Standard scroll="parent" beobachtet sie den Scroller, den du übergibst oder bereitstellst, sonst den nächsten scrollenden Vorfahren, sonst das Fenster, und setzt die Eigenschaft dort, solange sie gemountet und aktiv ist.

    tsx
    "use client";
    import { useState } from "react";
    import { RotateCw } from "lucide-react";
    import { Button } from "@/components/ui/button";
    import { List, type ListItemData } from "@/components/ui/list";
    import { PullToRefresh, type PullToRefreshApi } from "@/components/ui/pull-to-refresh";
    type InboxProps = { initial: ListItemData[]; load: () => Promise<ListItemData[]> };
    export function Inbox({ initial, load }: InboxProps) {
    const [items, setItems] = useState(initial);
    const [api, setApi] = useState<PullToRefreshApi>();
    return (
    <div className="flex h-dvh flex-col">
    <header className="flex h-14 shrink-0 items-center justify-between px-4">
    <h1 className="text-lg font-semibold">Posteingang</h1>
    {/* derselbe Refresh für Tastatur, Schaltersteuerung und Maus */}
    <Button variant="ghost" size="icon" radius="full" aria-label="Neu laden" onClick={() => void api?.refresh()}>
    <RotateCw />
    </Button>
    </header>
    <PullToRefresh
    scroll="self"
    variant="ios"
    shortcut="shift+r"
    className="min-h-0 flex-1"
    setApi={setApi}
    onRefresh={async () => setItems(await load())}
    labels={{ refreshing: "Suche nach neuen Mails…", done: "Alles aktuell", error: "Mails konnten nicht abgerufen werden" }}
    >
    <List variant="plain" items={items} />
    </PullToRefresh>
    </div>
    );
    }

    Der Indikator dreht sich, bis das Promise von onRefresh abgeschlossen ist; wird es abgelehnt, erscheint der Fehlerzustand. Übergib refreshing, wenn die App selbst einen Reload startet, und disabled, während jemand bearbeitet oder filtert: Schaltest du disabled mitten im Ziehen ein, federt die Liste ohne Refresh zurück.

    Wie fügst du Pull to Refresh einen haptischen Tick hinzu?

    Lös einen kurzen Tick aus, wenn der Pull die Schwelle überschreitet, also genau in dem Moment, ab dem Loslassen einen Refresh bedeutet; nie bei jedem Frame und nie beim Loslassen. Die Komponente ruft haptic("medium") aus dem Haptics-Helper auf, wenn der Pull scharf wird, und haptic("error"), wenn ein gezogener Refresh fehlschlägt. haptics={false} schaltet beides ab, und configureHaptics({ enabled }) ist der Schalter für die ganze App.

    Betrachte den Tick als Bonus, denn die Unterstützung ist uneinheitlich. Stand Oktober 2026 führt caniuse (opens in a new tab) navigator.vibrate in Chrome für Android und Samsung Internet, in Firefox ab Version 129 entfernt und in Safari nie vorhanden. Auf dem iPhone klickt der Helper per Skript ein verstecktes <input type="checkbox" switch>, um den System-Tick abzuspielen. Der Switch kam mit Safari 17.4 (opens in a new tab), und die Ankündigung von WebKit erwähnt keine Haptik, also garantiert nichts, dass das so bleibt. ios-haptics (opens in a new tab) nutzt denselben Trick und schrieb in seiner README vom Juni 2026 (Version 3.1.1), dass es nur unter iOS 17.4 bis 26.4 funktioniert, weil Apple das in iOS 26.5 gepatcht hat. Die Version vom September 2026 (3.2.0) leitet stattdessen den echten Tap der Person als vertrauenswürdigen Klick an den Switch weiter, was darauf hindeutet, dass ein Klick per Skript keinen Tick mehr abspielt. Ein Pull erzeugt nie einen Tap, also rechne damit, dass der Tick unter iOS 26.5 und neuer stumm bleibt, und leg nie eine Information hinein, die der Indikator nicht zeigt.

    Vibration braucht außerdem Sticky User Activation (opens in a new tab), und touchmove ist kein Aktivierungs-Event (touchend, das pointerup eines Fingers, mousedown und keydown sind es). Ist ein Pull das Erste, was jemand auf einer frisch geladenen Seite tut, bleibt der Tick stumm; haptic() gibt dann false zurück, statt Chrome einen blockierten Aufruf loggen zu lassen. Unser Guide zur Web Vibration API behandelt den Rest der Plattformlücke und eine Einstellung, mit der Nutzer Haptik abschalten.

    Wie machst du ein eigenes Pull to Refresh barrierefrei?

    Gib demselben Refresh einen Button, eine Taste und eine Ansage, denn Pull to Refresh ist eine Ziehbewegung. WCAG 2.2 Erfolgskriterium 2.5.7 (opens in a new tab) (Stufe AA) nimmt das Ziehen zum Aktualisieren des Browsers aus, weil der User Agent es bereitstellt. Sobald dein Inhalt ein eigenes umsetzt, gilt das Kriterium aber, also brauchst du eine Alternative, die mit einem einzelnen Zeiger ohne Ziehen auskommt. Der Swipe-to-Refresh-Guide von Android (opens in a new tab) verlangt dasselbe von nativen Apps: eine Refresh-Aktion im Overflow-Menü der App Bar, für Leute mit Tastatur oder D-Pad.

    Die Komponente bietet für jede Eingabeart einen Weg. setApi gibt dir { refresh() }, das genau das ausführt, was ein Pull ausführt (Indikator, Promise, Done-Zustand). So können Header-Button und Pull nie auseinanderlaufen; ein Aufruf während eines laufenden Refresh gibt das laufende Promise zurück. shortcut bindet eine Taste wie shift+r. Eine Live-Region mit polite sagt Refreshing… an, danach Updated oder den Fehler, und das Root-Element trägt so lange aria-busy. Auf dem Laptop löst ein weiterer Scroll nach oben ganz am Anfang mit Trackpad oder Mausrad einen Pull aus (wheel, standardmäßig an; Momentum, das einen Scroll bis nach oben trägt, tut das nie), und pullWithMouse erlaubt das Ziehen mit der Maus, für Kiosk-Geräte. Der Button im Header des Posteingang-Beispiels nutzt size="icon" des Buttons, also 40px mit Maus und 44px auf Touchscreens, die Größe, die der Guide zur minimalen Touch-Target-Größe empfiehlt.

    Zieh die Liste mit der Maus nach unten (pullWithMouse ist in dieser Demo an); auf dem Handy ziehst du mit dem Finger. Der Ring füllt sich, während die Zeilen stehen bleiben, und der Button Reload im Header führt denselben Refresh ohne Geste aus.
    $ npx wingo-ui@latest add pull-to-refresh
    ProDoku: Pull To Refresh

    Wie nutzt du Pull to Refresh mit einer langen virtualisierten Liste?

    Lass genau ein Element scrollen und teile es, damit beide Komponenten dieselbe Scrollposition beobachten. Die Virtual List mit scroll="window" folgt dem nächsten ScrollContainerProvider, und Pull To Refresh mit dem Standard scroll="parent" ebenfalls:

    tsx
    "use client";
    import { useState } from "react";
    import { ListItem } from "@/components/ui/list";
    import { PullToRefresh } from "@/components/ui/pull-to-refresh";
    import { VirtualList } from "@/components/ui/virtual-list";
    import { ScrollContainerProvider } from "@/hooks/use-scroll-state";
    type Order = { id: string; customer: string; city: string; total: string };
    type OrdersProps = {
    orders: Order[];
    hasMore: boolean;
    reload: () => Promise<void>;
    loadPage: () => Promise<void>;
    };
    export function Orders({ orders, hasMore, reload, loadPage }: OrdersProps) {
    // ein Element scrollt, und beide Komponenten folgen ihm über den Provider
    const [scroller, setScroller] = useState<HTMLDivElement | null>(null);
    return (
    <div ref={setScroller} className="h-dvh overflow-y-auto">
    <ScrollContainerProvider value={scroller}>
    <PullToRefresh variant="material" onRefresh={reload}>
    <VirtualList
    aria-label="Bestellungen"
    scroll="window"
    items={orders}
    renderItem={(order) => <ListItem id={order.id} title={order.customer} description={order.city} value={order.total} />}
    hasMore={hasMore}
    onLoadMore={loadPage}
    />
    </PullToRefresh>
    </ScrollContainerProvider>
    </div>
    );
    }

    Nimm hier die Material-Variante. Die Virtual List misst mit getBoundingClientRect(), wo sie im Scroller beginnt, und das zählt Transforms mit; sie misst erneut, wenn sich ihre Größe ändert. Die Varianten arrow und ios halten die Zeilen per Transform 72px weiter unten, während onRefresh läuft, und genau dann kommen neue Zeilen an. Der Material-Ring schwebt über Zeilen, die sich nie bewegen. Für das andere Ende lädt loadMode="pull" auf der Virtual List die nächste Seite, wenn jemand über die letzte Zeile hinaus zieht und loslässt.

    Welche Pull-to-Refresh-Fallen tauchen in Produktion auf?

    Prüf diese fünf vor dem Release, egal ob du unsere Komponente nutzt oder deine eigene React-Pull-to-Refresh-Komponente:

    • Ein sticky oder halbtransparenter Header über der Liste. Der Indikator verschwindet darunter. indicatorOffset schiebt seine Ruhelinie um die Höhe des Headers nach unten.
    • Ein Pull während des Bounce ganz oben. Auf iOS wird die Scrollposition negativ, während die Liste über den Anfang hinaus federt. Eine strikte Prüfung auf scrollTop === 0 lehnt Pulls ab, die genau dann beginnen. Behandle alles bei oder unter 0 als Anfang.
    • Eine fixierte Leiste im gezogenen Inhalt. Die Varianten arrow und ios bewegen den Inhalt per Transform, und ein transformiertes Element wird zum Containing Block seiner Kinder mit position: fixed. Eine Tab Bar oder ein schwebender Button darin fährt also beim Ziehen mit nach unten. Rendere fixierte Leisten außerhalb der Komponente.
    • Verschachtelte Pull-to-Refresh-Bereiche, etwa ein Feed in einem Tab einer Seite, die sich ebenfalls aktualisiert. Der innere sollte gewinnen; die Komponente sorgt dafür, dass der äußere die Geste ignoriert.
    • Ein Refresh, der nie endet. Hängt onRefresh, hängt auch der Spinner. Setz das Timeout auf den Request, zum Beispiel fetch(url, { signal: AbortSignal.timeout(10_000) }), nicht auf den Indikator: Das abgelehnte Promise zeigt dann den Fehlerzustand, und der Indikator sagt die Wahrheit.

    Für den Rest der mobilen Ebene (Bottom Sheets, Safe Areas, dvh, Tab Bars) lies den Guide zu Mobile-first React-Komponenten oder stöber in Mobile UI in React.

    Was installierst du als Nächstes?

    Wenn deine Liste schon steht, umschließ sie einfach. npx wingo-ui@latest add pull-to-refresh kopiert die Komponente mit dem Spinner und den Hooks und Helpern, die sie importiert (Haptics, Motion, Scroll-State, Shortcuts), in dein Projekt und installiert motion und lucide-react. Pull To Refresh, List und Virtual List gehören zu Wingo UI Pro, also melde dich zuerst mit npx wingo-ui@latest login an; der Spinner, den die Komponente nutzt, ist kostenlos.

    Komponenten in diesem Artikel

    • Pull To Refresh

      A React pull to refresh wrapper: pull a list past its top to reload it, with rubberband resistance, iOS spokes or a Material ring, haptics.

      Pro
    • List

      A React list for settings, contacts, inboxes and orders: iOS grouped panels, selection, row menus, swipe actions and drag to reorder.

      Pro
    • Virtual List

      A React virtual list for long and endless lists at 60fps, with sticky group headers, infinite loading and scroll restoration.

      Pro
    • Haptics

      Haptic feedback for the web in one call: short vibration ticks on Android and the system tick on iPhone, silent everywhere else.

      Pro

    Häufige Fragen

    Wie kann ich Pull to Refresh in Chrome deaktivieren?

    Setz overscroll-behavior-y: contain auf das Element, das scrollt. Scrollt das Fenster, ist das html. Mit none verschwindet zusätzlich der Overscroll-Glow. Chrome unterstützt die Eigenschaft seit Version 63.

    Stoppt overscroll-behavior Pull to Refresh in Safari auf iOS?

    Nicht zuverlässig. Safari unterstützt die Eigenschaft seit Version 16, aber laut WebKit-Bug 275947, offen seit Juni 2024, schaltet sie Safaris eigenes Pull to Refresh nicht ab. Ruf preventDefault in einem nicht passiven touchmove-Listener auf, sobald die Geste als Pull erkannt ist.

    Warum funktioniert preventDefault in onTouchMove in React nicht?

    Seit React 17 registriert React onTouchStart, onTouchMove und onWheel als passive Listener, und Browser ignorieren preventDefault in einem passiven Listener. Häng den Listener selbst mit addEventListener und { passive: false } in einem Effect an das scrollende Element.

    Ist ein eigenes Pull to Refresh barrierefrei?

    Nur mit einer Alternative. WCAG 2.2 Erfolgskriterium 2.5.7 Dragging Movements (Stufe AA) nimmt das Ziehen zum Aktualisieren des Browsers aus, gilt aber für eines, das du selbst baust. Ergänze also einen Refresh-Button oder ein Tastenkürzel, das denselben Reload ausführt, und sag das Ergebnis in einer Live-Region an.

    Ist Pull To Refresh von Wingo UI kostenlos?

    Nein. Es ist eine Pro-Komponente, genau wie die List, die Virtual List und der Haptics-Helper, mit denen sie zusammenarbeitet; der Spinner, den sie nutzt, ist kostenlos. Mit einem Pro-Account, angemeldet über npx wingo-ui@latest login, kopiert npx wingo-ui@latest add pull-to-refresh die Komponente und alles, was sie importiert, in dein Projekt.

    • Mobile UI
    • Pull to Refresh
    • PWA
    • React
    • Gesten

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Mobile UI mit React

    Native App Feeling für Web Apps: 12 React-Fixes

    Native App Feeling auf dem Handy: 12 Details für deine Web App, von sofortigen Taps über Action Sheets und wischbare Tabs bis zu Haptik und Large Titles.

    SRSerban Rusu·13. Okt. 2026·11 Min. Lesezeit
    Mobile UI mit React

    React Swipe to Delete: iOS-Swipe-Actions mit Undo

    React Swipe to Delete für Listenzeilen: iOS-Swipe-Actions, ein Full Swipe zum Löschen, Undo per Toast und Buttons für alle mit Maus oder Tastatur.

    SRSerban Rusu·13. Okt. 2026·10 Min. Lesezeit
    Mobile UI mit React

    Mobile First React: 9 Regeln für Komponenten mit Code

    Mobile First React Regel für Regel, mit Code: Bottom Sheets statt Popover, 44px Touch-Ziele, Safe Areas, dvh, Leisten über der Tastatur, Tabellen als Karten.

    SRSerban Rusu·9. Okt. 2026·21 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Guides, Tutorials und Vergleiche aus dem Wingo UI Blog, sobald sie erscheinen. Die meisten Artikel sind auf Englisch.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Theme-Generator

    Ressourcen

    • Doku
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI