Appearance
Data Components
Data components display and manage server-side data with automatic pagination, sorting, filtering, and infinite scroll.
Available Components
| Component | Description | Link |
|---|---|---|
VqDataTable | Server-side paginated data table with sorting and filter integration | → Docs |
useVqDataTable<T> | Type-safe wrapper for VqDataTable | → Docs |
collectVqHeaders | Utility to prepend a # serial column to table headers | → Docs |
VqSerialNo | Serial number <td> cell for use in table row slots | → Docs |
VqDatatableItemAction | Row action button (delete/status) with confirmation dialog | → Docs |
VqList | Infinite-scroll list with filter integration | → Docs |
useVqList<T> | Type-safe wrapper for VqList | → Docs |
VqTableFilter | Filter form that connects to VqDataTable or VqList by shared id | → Docs |
VqListLoadMoreBtn | "Load More" button for VqList — uses inject, no props needed | → Docs |
MessageQueue | Root-level snackbar notification queue — place once in App.vue | → Docs |
How It Works
Table + Filter Pattern
Connect VqTableFilter and VqDataTable with the same id. When filter fields change, the table reloads automatically.
vue
<script setup>
import { VqDataTable, VqTableFilter, VqTextField, collectVqHeaders } from "@qnx/vuetify";
const headers = collectVqHeaders([
{ title: "Name", key: "name" },
{ title: "Email", key: "email" },
{ title: "Actions", key: "actions", sortable: false },
]);
</script>
<template>
<VqTableFilter id="users">
<VqTextField name="search" label="Search" />
</VqTableFilter>
<VqDataTable id="users" action="users/list" :headers="headers">
<template #item="{ item, index }">
<tr>
<td>{{ index }}</td>
<td>{{ item.name }}</td>
<td>{{ item.email }}</td>
<td>
<VqDatatableItemAction
id="users"
:item-id="String(item.id)"
action="users/delete"
method="DELETE"
/>
</td>
</tr>
</template>
</VqDataTable>
</template>Infinite Scroll List Pattern
vue
<template>
<VqTableFilter id="posts">
<VqTextField name="search" label="Search" />
</VqTableFilter>
<VqList id="posts" action="posts/list" :page-size="15" v-slot="{ items, loading }">
<v-list-item v-for="post in items" :key="post.id" :title="post.title" />
<v-skeleton-loader v-if="loading" type="list-item@3" />
<VqListLoadMoreBtn />
</VqList>
</template>Import
typescript
import {
VqDataTable,
useVqDataTable,
collectVqHeaders,
VqSerialNo,
VqDatatableItemAction,
VqList,
useVqList,
VqTableFilter,
VqListLoadMoreBtn,
MessageQueue,
} from "@qnx/vuetify";