--- title: "MazPullToRefresh" description: "MazPullToRefresh adds a native-feeling pull to refresh gesture to your app or to any scroll container, with a progress ring, haptic feedback and translated, accessible feedback." package: "maz-ui" url: "https://maz-ui.com/components/maz-pull-to-refresh" --- # MazPullToRefresh > MazPullToRefresh adds a native-feeling pull to refresh gesture to your app or to any scroll container, with a progress ring, haptic feedback and translated, accessible feedback. - Package: `maz-ui` - Import: `import MazPullToRefresh from 'maz-ui/components/MazPullToRefresh'` - Nuxt: auto-imported by `@maz-ui/nuxt`, no import needed in a Nuxt app - Web: https://maz-ui.com/components/maz-pull-to-refresh > Before use it, you should install the MazUi plugin in your project, follow instructions in [Getting Started](../guide/getting-started.md) ## Key Features - Works on the window **and on any scroll container**: the closest scrollable ancestor is detected automatically, so it fits app shells with a fixed layout and a scrolling `
` - Starts only when the container is scrolled to the top, never in the middle of a list - Rubber band resistance beyond the trigger distance, and a progress ring that fills while pulling - Ignores horizontal swipes and multi-touch gestures, and prevents the native bounce (and the browser's own pull to refresh) while pulling - Haptic feedback when the trigger distance is reached (devices supporting `navigator.vibrate`) - Texts from [@maz-ui/translations](../ecosystem/translations.md), overridable with the `translations` prop or the slots - Accessible: the refresh is announced to screen readers, `aria-busy` is set while refreshing, and `refresh()` is exposed for a button usable with a keyboard or a mouse - Optional `standalone-mode` to enable it only in an installed PWA (browsers already have their own pull to refresh) - Built on the headless [usePullToRefresh](../composables/use-pull-to-refresh.md) composable ## Demo ## Basic usage Wrap your app (or a page) inside the component and give it the function that reloads your data. The spinner stays visible until the returned promise settles. ```vue ``` With Nuxt, `refreshNuxtData` reloads every `useFetch` / `useAsyncData` of the page: ```vue ``` ## Inside a scroll container The pull can only start when its scroll container is at the top. By default, the component uses its **closest scrollable ancestor** (`overflow-y: auto | scroll`), or the window if there is none. Typical app shells with a fixed layout and a scrolling `
` work without configuration: ```vue ``` Use `container-selector` when the scroll container is not an ancestor of the component: ```vue ``` ## Installed apps only Browsers already provide their own pull to refresh. With `standalone-mode`, the component is only active when the app runs as an installed PWA (`display-mode: standalone`): ```vue ``` ## Tuning the gesture | Prop | Default | Effect | | -------------- | ---------------- | --------------------------------------------------------------------------------------- | | `distance` | `80` | Pull distance (px, after resistance) needed to trigger a refresh | | `max-distance` | `distance * 1.6` | Upper bound of the rubber band beyond `distance` | | `resistance` | `0.5` | Ratio between the finger movement and the pull distance (lower is stiffer) | | `min-duration` | `400` | Minimum duration (ms) of the refreshing state, so fast refreshes still show the feedback | | `haptic` | `true` | Short vibration when `distance` is reached | ## Customize the indicator The three states have their own slot. Each one receives the pull `progress` (0 to 1) and the current `distance` in px. ```vue ``` `spinner-color` sets the color of the progress ring, the ready arrow and the default spinner (`primary` by default). ## Translations Texts come from [@maz-ui/translations](../ecosystem/translations.md) (`pullToRefresh.pull`, `pullToRefresh.release`, `pullToRefresh.refreshing`). Override them per instance with the `translations` prop: ```vue ``` ## Accessibility The gesture is touch only. To give keyboard and mouse users the same action, call the exposed `refresh()` from a button: the indicator and the events behave exactly as with the gesture. ```vue ``` While refreshing, the root element has `aria-busy="true"` and the refreshing text is announced through a polite live region. The visual indicator is hidden from assistive technologies. ## Events The events follow the life of a refresh: `start`, then `loaded` and `response` (with the value resolved by `on-refresh`) or `error`, and always `finish`. An error thrown by `on-refresh` is emitted, never thrown again. ## Headless usage Need a different indicator, or a gesture on an element without wrapping it? Use the [usePullToRefresh](../composables/use-pull-to-refresh.md) composable. ## MazPullToRefresh API `import MazPullToRefresh from 'maz-ui/components/MazPullToRefresh'` ### Props - `on-refresh` (`(() => unknown)`): Function called when the user releases after pulling far enough. The spinner stays visible until the returned promise settles. Without it, the component does nothing. - `distance` (`number`, default: `80`): Pull distance (in px, after resistance) required to trigger a refresh. - `max-distance` (`number`, default: `distance * 1.6`): Maximum pull distance (in px), reached with a rubber band effect beyond `distance`. - `resistance` (`number`, default: `0.5`): Ratio between the finger movement and the pull distance, between 0 and 1. Lower is stiffer. - `min-duration` (`number`, default: `400`): Minimum duration (in ms) of the refreshing state, so the feedback stays visible on fast refreshes. - `container-selector` (`string`): CSS selector of the scroll container. By default, the closest scrollable ancestor of the component, or the window. The pull only starts when this container is scrolled to the top. - `header-class` (`ClassValue`): Class of the header that holds the indicator. - `spinner-color` (`"primary" | "secondary" | "accent" | "info" | "success" | "warning" | "destructive" | "contrast" | "transparent"`, default: `"primary"`): Color of the progress ring and the spinner. - `disabled` (`boolean`, default: `false`): Disable the pull to refresh. - `standalone-mode` (`boolean`, default: `false`): Only enable the pull to refresh when the app runs as an installed PWA (standalone display mode), browsers already provide their own pull to refresh. - `haptic` (`boolean`, default: `true`): Vibrate briefly when the pull reaches `distance` (devices supporting `navigator.vibrate`). - `translations` (`{ pull?: string | undefined; release?: string | undefined; refreshing?: string | undefined; }`, default: `Translations from`): Translations of the pull to refresh. - `offset` (`number`) ### Events - `@loaded`: Emitted when `onRefresh` resolved - `@error` (payload: `error: unknown`): Emitted when `onRefresh` threw or rejected - `@start`: Emitted when the refresh starts - `@response` (payload: `response: unknown`): Emitted with the value resolved by `onRefresh` - `@finish`: Emitted when the refresh ends, after `loaded` or `error` ### Slots - `#pull-before`: Content shown while pulling, before the threshold Bindings: `progress: number`, `distance: number`. - `#pull-ready`: Content shown once releasing triggers a refresh Bindings: `progress: number`, `distance: number`. - `#pull-loading`: Content shown while refreshing Bindings: `progress: number`, `distance: number`. - `#default`: Content of the page ### Exposed (template ref) - `refresh`: Run the refresh programmatically (a "refresh" button for keyboard and mouse users) - `isRefreshing`: `onRefresh` is running - `progress`: Pull progress towards `distance`, from 0 to 1