Managing Client-Side Tables with Vuetify’s v-data-table
Use Vuetify v-data-table for built-in sorting, search, and pagination, but know when client-side rendering becomes a bottleneck.
31 Mar 2026, 20:16 UTC

A table that works until it doesn't
You inherit a dashboard that lists user accounts. The first 50 rows render instantly, and Vuetify’s v-data-table handles search, sort, and pagination with almost no code. Then the dataset grows to 800 rows. The browser freezes on every keystroke in the search box, and the pagination controls feel sluggish.
The useful takeaway: v-data-table is excellent for client-side data up to a few hundred rows, but it is not a substitute for server-side pagination when the dataset grows. You can start client-side and move to server-side later without rewriting the whole component.
1. Decouple column labels from data keys
Vuetify 3 assumes you are using Vue 3. The headers prop accepts an array of objects. Each object maps a human-readable label to a data key in your items array.
<template>
<v-data-table
:headers='headers'
:items='users'
item-key='id'
show-select
density='compact'
>
<template v-slot:item.status='{ item }'>
<v-chip :variant='item.status === "active" ? "tonal" : "outline"'>
{{ item.status }}
</v-chip>
</template>
</v-data-table>
</template>
<script setup>
import { ref } from 'vue'
const headers = ref([
{ title: 'Name', key: 'name', align: 'start' },
{ title: 'Role', key: 'role' },
{ title: 'Status', key: 'status', sortable: true },
{ title: 'Updated', key: 'updatedAt' },
])
const users = ref([
{ id: 1, name: 'Ada', role: 'Engineer', status: 'active', updatedAt: '2026-10-17' },
// ... more objects
])
</script>
The item-key tells Vuetify which field uniquely identifies a row. Without it, selection and editing can behave unpredictably.
2. Customize cells with named slots
Slot names follow the pattern item.. In the example above, item.status replaces the default text cell with a v-chip. You can also use item.actions to place edit or delete buttons in a dedicated column.
This keeps the table declaration readable while letting individual cells use interactive components. If you are upgrading from Vuetify 2, check the slot syntax; Vuetify 3 uses scoped slots consistently, but some props and events changed.
3. Pagination and the client-size limit
By default, Vuetify manages sorting, filtering, and pagination in the browser. The footer shows a page-size selector, and changing items-per-page updates the visible rows immediately.
That convenience has a ceiling. Every row stays in the DOM or is re-rendered by Vue’s diffing, but with hundreds of rows and complex cell components, search keystrokes can trigger expensive re-renders.
Practical check: open your browser’s developer tools, record performance while typing in the table search field, and watch for long tasks above 50 milliseconds. If you see them consistently at 300+ rows, it is time to paginate on the server.
Worked example: status chips and page size
This configuration shows 10 rows per page, highlights active users, and exposes a page-size dropdown.
<v-data-table
:headers='headers'
:items='users'
:items-per-page='10'
show-select
>
<template #item.status='{ item }'>
<v-chip size='small' :variant='item.status === "active" ? "tonal" : "outline"'>
{{ item.status }}
</v-chip>
</template>
</v-data-table>
Run npm install vuetify@^3 in your project root to add Vuetify 3. No special permissions are required. After installing, confirm the dependency with npm list vuetify. The risk is a version mismatch: Vuetify 3 requires Vue 3, so do not install it into a Vue 2 project.
Limitation: sorting depends on consistent data types
Default sorting compares values as they exist in items. If one row stores age: 29 as a number and another stores age: "29" as a string, sort order can surprise you. Normalize data before passing it to the table, or provide a custom sort function in the header object.
What to do next
- Build the table with a mock array of 50 objects.
- Verify that the
headerskeys match your object properties exactly. - Type in the search field and confirm results filter in real time.
- Change the page-size dropdown and confirm the visible row count updates.
- If you expect more than a few hundred rows, plan for server-side pagination using Vuetify’s server-side table variant or your own API-backed pagination state.
Start client-side, measure with real data, and move the pagination logic to your API when the browser can no longer keep up.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.