Implement Server‑Side Pagination, Sorting, and Search with Vuetify 3's v‑data‑table‑server
Wire Vuetify 3's v‑data‑table‑server to a backend in Vue 3. The guide covers load-items, items‑length, debounced search, abort handling, and error recovery with a retry button.
20 Oct 2025, 06:03 UTC

Problem
When a table contains thousands of rows, loading the entire dataset into the browser is impractical. Vuetify 3 offers v-data-table-server, which delegates pagination, sorting, and filtering to the server. The component emits the current page, items‑per‑page, sort keys, and search string, and the developer supplies a load-items function that turns those options into a backend request.
Prerequisites
- A Vue 3 project with Vuetify 3 installed and registered.
- A REST or GraphQL endpoint that accepts
page,size,sort,order, andsearchparameters and returns a JSON object withitems(the page data) andtotal(the count of all matching rows). - A header definition whose
keyvalues match the sort names the backend understands. - Knowledge that
v-data-table-servermanages UI state – pagination footer, loading overlay, and disabled controls – based on the props you bind.
Wiring the loadItems handler
The component expects a function that receives an options object and returns a promise resolving to an object with items and total. The function can be passed via the load-items prop or you can listen for the @update:options event and call the same logic. The example below uses the load-items prop for clarity.
<v-text-field
v-model="searchInput"
label="Search"
prepend-inner-icon="mdi-magnify"
/>
<v-data-table-server
v-model:items-per-page="itemsPerPage"
v-model:page="page"
:headers="headers"
:items="rows"
:items-length="totalItems"
:loading="loading"
:search="debouncedSearch"
:load-items="loadItems"
item-value="id"
/>
<v-snackbar v-model="errorVisible" timeout="6000">
{{ errorMessage }}
<template #actions>
<v-btn @click="retry">Retry</v-btn>
</template>
</v-snackbar>
</template>
Why the double‑ref pattern?
Binding the raw searchInput directly to :search would trigger a new request on every keystroke. The debounced copy ensures that loadItems is called only once the user stops typing, reducing server load and avoiding race conditions.
Page Reset on Search
When the search string changes, the current page number often no longer exists in the filtered set. The example above resets page to 1 inside the search watcher. If you prefer to let the component handle this, check the documentation for your Vuetify 3 minor release; some versions automatically reset the page when :search changes.
Abort Handling and Out‑of‑Order Responses
The AbortController cancels any previous fetch before starting a new one. If a user changes pages or sorts quickly, an older, slower response will be discarded, preventing stale data from overwriting newer results. Note that aborting a fetch only stops client‑side processing; the server continues to execute the query.
Error Recovery with a Retry Button
When a request fails, the snackbar shows the error and offers a Retry action. The retry method simply re‑invokes loadItems with the last successful options, which is safe because the function re‑creates the request each time.
Expected Checks
- Network request – In the browser’s Network tab, clicking a page number or column header should send exactly one request with the correct
page,size,sort, andorderquery parameters. - Pagination footer – The footer should display the correct total page count derived from the
totalvalue returned by the API. - Search debounce – Typing in the search field should produce a single request after a ~300 ms pause, and the table should reset to page 1.
- Error handling – Simulate a failed request (e.g., by blocking the endpoint or going offline). The loading indicator must disappear, the snackbar appears, and clicking
Retryrestores the data.
Common Pitfalls
- Passing the entire dataset to
:itemswhile also usingv-data-table-serverdefeats the purpose and can cause memory or rendering issues. - Using the wrong event or prop name for your Vuetify major version.
v-data-table-serveris a Vuetify 3 component; in Vuetify 2 you would usev-data-tablewithserver-items-lengthand@update:options. - Not binding
items-lengthto a reactive ref that updates after each fetch. The pagination footer relies on this value to calculate the number of pages. - Assuming the backend will automatically validate sort keys. The client can send any
key; the server must map it to a safe column name or reject it. - Ignoring the fact that aborting a fetch does not cancel server‑side work. If the server is rate‑limited or has long queries, the extra work still consumes resources.
Limitations
Using v-data-table-server shifts the complexity to the backend: you must implement pagination, sorting, filtering, and counting consistently. For very large tables or tables that change frequently, cursor‑based pagination can be more efficient than offset paging, but it requires a different mapping of options to backend calls. Finally, the automatic page reset behavior on search change varies across Vuetify 3 minor releases; verify against your installed version’s documentation before shipping.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.