The <VueListRefresh> component provides a button to manually refresh the current list data. It re-fetches data with the current filters, page, and settings, and passes isRefresh: true to the request handler.
Basic usage
< template >
< VueList endpoint = "users" >
< VueListRefresh />
< VueListItems # default = " { items } " >
< div v-for = " user in items " : key = " user . id " >
{{ user . name }}
</ div >
</ VueListItems >
</ VueList >
</ template >
Props
This component has no props. It uses Vue’s inject to access the list state from the parent <VueList> component.
Slot
The default slot receives a scope object:
< VueListRefresh # default = " { refresh , isLoading } " >
<button @click="refresh()" :disabled="isLoading">
{{ isLoading ? 'Refreshing...' : 'Refresh' }}
</button>
</ VueListRefresh >
Scope object
refresh(context) - Function to refresh data. Optionally pass additional context
isLoading - Boolean indicating if data is currently being fetched
Behavior
Refetches current page : Doesn’t reset to page 1 or change any filters
Passes isRefresh: true : Your request handler receives context.isRefresh === true
In loadMore mode : Resets to page 1 (shows only first page of items)
In pagination mode : Stays on current page
Examples
< VueListRefresh # default = " { refresh , isLoading } " >
<button
@click="refresh()"
:disabled="isLoading"
class="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-400"
>
{{ isLoading ? 'Refreshing...' : 'Refresh' }}
</button>
</ VueListRefresh >
With icon
< VueListRefresh # default = " { refresh , isLoading } " >
<button
@click="refresh()"
:disabled="isLoading"
class="flex items-center gap-2 px-4 py-2 border rounded hover:bg-gray-50"
>
<svg
:class="{ 'animate-spin': isLoading }"
class="w-5 h-5"
fill="none"
stroke="currentColor"
>
<path d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
<span>{{ isLoading ? 'Refreshing' : 'Refresh' }}</span>
</button>
</ VueListRefresh >
< VueListRefresh # default = " { refresh , isLoading } " >
<button
@click="refresh()"
:disabled="isLoading"
:title="isLoading ? 'Refreshing...' : 'Refresh data'"
class="p-2 rounded-full hover:bg-gray-100 disabled:opacity-50"
>
<svg
:class="{ 'animate-spin': isLoading }"
class="w-5 h-5 text-gray-600"
fill="none"
stroke="currentColor"
>
<path d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
</ VueListRefresh >
< VueList endpoint = "products" # default = " { count } " >
<div class="flex items-center justify-between mb-4">
<div>
<h1 class="text-2xl font-bold">Products</h1>
<p class="text-sm text-gray-600">{{ count }} total items</p>
</div>
<VueListRefresh #default="{ refresh, isLoading }">
<button
@click="refresh()"
:disabled="isLoading"
class="btn-secondary"
>
<svg :class="{ 'animate-spin': isLoading }" class="w-4 h-4">
<!-- refresh icon -->
</svg>
Refresh
</button>
</VueListRefresh>
</div>
<VueListItems #default="{ items }">
<!-- render items -->
</VueListItems>
</ VueList >
With last updated timestamp
< template >
< VueList endpoint = "orders" @ on-response = " updateTimestamp " >
< div class = "flex items-center justify-between" >
< p class = "text-sm text-gray-600" >
Last updated: {{ lastUpdated || 'Never' }}
</ p >
< VueListRefresh # default = " { refresh , isLoading } " >
< button @ click = " refresh () " : disabled = " isLoading " >
{{ isLoading ? 'Updating...' : 'Refresh' }}
</ button >
</ VueListRefresh >
</ div >
< VueListItems # default = " { items } " >
<!-- render items -->
</ VueListItems >
</ VueList >
</ template >
< script setup >
import { ref } from 'vue'
const lastUpdated = ref ( '' )
function updateTimestamp () {
lastUpdated . value = new Date (). toLocaleTimeString ()
}
</ script >
Auto-refresh every 30 seconds
< template >
< VueList ref = "listRef" endpoint = "notifications" >
< VueListItems # default = " { items } " >
<!-- render items -->
</ VueListItems >
</ VueList >
</ template >
< script setup >
import { ref , onMounted , onUnmounted } from 'vue'
const listRef = ref ()
let intervalId = null
onMounted (() => {
// Auto-refresh every 30 seconds
intervalId = setInterval (() => {
listRef . value ?. refresh ()
}, 30000 )
})
onUnmounted (() => {
if ( intervalId ) {
clearInterval ( intervalId )
}
})
</ script >
Pull to refresh (mobile)
< template >
< div
@ touchstart = " handleTouchStart "
@ touchmove = " handleTouchMove "
@ touchend = " handleTouchEnd "
class = "pull-to-refresh-container"
>
< div v-if = " isPulling " class = "pull-indicator" : style = " { height: pullDistance + 'px' } " >
< span v-if = " pullDistance > 80 " > Release to refresh </ span >
< span v-else > Pull to refresh </ span >
</ div >
< VueList ref = "listRef" endpoint = "posts" >
< VueListItems # default = " { items } " >
<!-- render items -->
</ VueListItems >
</ VueList >
</ div >
</ template >
< script setup >
import { ref } from 'vue'
const listRef = ref ()
const isPulling = ref ( false )
const pullDistance = ref ( 0 )
let startY = 0
function handleTouchStart ( e ) {
if ( window . scrollY === 0 ) {
startY = e . touches [ 0 ]. clientY
isPulling . value = true
}
}
function handleTouchMove ( e ) {
if ( isPulling . value ) {
const currentY = e . touches [ 0 ]. clientY
pullDistance . value = Math . min (( currentY - startY ) / 2 , 100 )
}
}
function handleTouchEnd () {
if ( pullDistance . value > 80 ) {
listRef . value ?. refresh ()
}
isPulling . value = false
pullDistance . value = 0
}
</ script >
With success feedback
< template >
< VueList endpoint = "users" @ on-response = " handleRefresh " >
< VueListRefresh # default = " { refresh , isLoading } " >
< button @ click = " handleRefreshClick ( refresh ) " : disabled = " isLoading " >
{{ isLoading ? 'Refreshing...' : 'Refresh' }}
</ button >
</ VueListRefresh >
< div v-if = " showSuccess " class = "success-message" >
✔ Data refreshed successfully
</ div >
< VueListItems # default = " { items } " >
<!-- render items -->
</ VueListItems >
</ VueList >
</ template >
< script setup >
import { ref } from 'vue'
const showSuccess = ref ( false )
function handleRefreshClick ( refresh ) {
refresh ()
}
function handleRefresh () {
showSuccess . value = true
setTimeout (() => {
showSuccess . value = false
}, 3000 )
}
</ script >
Using refresh() programmatically
You can access the refresh method via template ref:
< template >
< VueList ref = "listRef" endpoint = "products" />
< button @ click = " refreshList " > Refresh </ button >
</ template >
< script setup >
import { ref } from 'vue'
const listRef = ref ()
function refreshList () {
listRef . value ?. refresh ()
}
</ script >
Passing additional context
You can pass additional context to the refresh call:
< VueListRefresh # default = " { refresh } " >
<button @click="refresh({ source: 'manual-button' })">
Refresh
</button>
</ VueListRefresh >
Your request handler receives this context:
app . use ( VueList , {
requestHandler ( context ) {
console . log ( context . isRefresh ) // true
console . log ( context . source ) // 'manual-button'
// Make API request
}
})
Use context.isRefresh in your request handler to bypass cache or add special headers for refresh requests.
In loadMore pagination mode, refresh resets to page 1 and clears all loaded items. In pagination mode, it refetches the current page.
Next steps
Error component Combine refresh with error handling
Loader Show loading state during refresh