Pagination
Pagination can be a super helpful tool when working with large sets of data. If you have 1,000 options, the component is going to render 1,000 DOM nodes. That's a lot of nodes to insert/remove, and chances are your user is only interested in a few of them anyway.
To implement pagination with Vs Vue3 Select, you can take advantage of the list-footer
slot. It appears below all other options in the dropdown list.
To make pagination work properly with filtering, you'll have to handle it yourself in the parent. You can use the filterable
boolean to turn off Vs Vue3 Select's filtering, and then hook into the search
event to use the current search query in the parent component.
<template>
<v-select
:options="paginated"
:filterable="false"
@search="(query) => (search = query)"
>
<template #list-footer>
<li class="pagination">
<button :disabled="!hasPrevPage" @click.prevent="offset -= limit">
Prev
</button>
<button :disabled="!hasNextPage" @click.prevent="offset += limit">
Next
</button>
</li>
</template>
</v-select>
</template>
<script>
import countries from '../data/countries'
export default {
data: () => ({
countries,
search: '',
offset: 0,
limit: 5,
}),
computed: {
filtered() {
return this.countries.filter((country) =>
country.toLocaleLowerCase().includes(this.search.toLocaleLowerCase()),
)
},
paginated() {
return this.filtered.slice(this.offset, this.limit + this.offset)
},
hasNextPage() {
const nextOffset = this.offset + this.limit
return Boolean(
this.filtered.slice(nextOffset, this.limit + nextOffset).length,
)
},
hasPrevPage() {
const prevOffset = this.offset - this.limit
return Boolean(
this.filtered.slice(prevOffset, this.limit + prevOffset).length,
)
},
},
methods: {
onSearch(query) {
this.search = query
this.offset = 0
},
},
}
</script>
<style scoped>
.pagination {
display: flex;
margin: 0.25rem 0.25rem 0;
}
.pagination button {
flex-grow: 1;
}
.pagination button:hover {
cursor: pointer;
}
</style>