Vitral 0.2
Data

DataView

Sorting and paging over your own template per item, shown as a list or a grid.

Import

main.ts
import { DataView } from '@vitral/vue';

List and grid

Bamboo Watch 1
Bamboo Watch 1Accessories
$20In stock
Gold Necklace 6
Gold Necklace 6Clothing
$25Out
Gaming Set 11
Gaming Set 11Fitness
$30Low
Game Controller 16
Game Controller 16Electronics
$35In stock
Blue Band 21
Blue Band 21Accessories
$40Out
Black Jacket 2
Black Jacket 2Clothing
$57Low
<script setup lang="ts">import { Button, DataView, SelectButton, Tag } from '@vitral/vue';import { ref } from 'vue'; interface Product {    id: number;    name: string;    category: string;    price: number;    stock: 'In stock' | 'Low' | 'Out';    image: number;} const categories = ['Accessories', 'Clothing', 'Fitness', 'Electronics'];const products: Product[] = Array.from({ length: 24 }, (_, i) => ({    id: i,    name: ['Bamboo Watch', 'Black Jacket', 'Blue Band', 'Game Controller', 'Gaming Set', 'Gold Necklace'][i % 6]! + ` ${i + 1}`,    category: categories[i % 4]!,    price: 20 + ((i * 37) % 180),    stock: (['In stock', 'Low', 'Out'] as const)[i % 3]!,    image: 20 + i})); const layout = ref<'list' | 'grid'>('grid');const sortOrder = ref<1 | -1>(1);const severity = (stock: Product['stock']) => (stock === 'In stock' ? 'success' : stock === 'Low' ? 'warn' : 'danger');</script> <template>    <DataView :value="products" :layout="layout" paginator :rows="6" sort-field="price" :sort-order="sortOrder" data-key="id">        <template #header>            <div style="display: flex; justify-content: space-between; align-items: center; gap: 0.5rem">                <Button :label="sortOrder === 1 ? 'Price: low to high' : 'Price: high to low'" icon="sort" severity="secondary" variant="text" @click="sortOrder = sortOrder === 1 ? -1 : 1" />                <SelectButton v-model="layout" :options="['list', 'grid']" :allow-empty="false" aria-label="Layout" />            </div>        </template>        <template #list="{ items }">            <ul style="margin: 0; padding: 0; list-style: none">                <li v-for="p in items as Product[]" :key="p.id" style="display: flex; align-items: center; gap: 1rem; padding: 0.75rem 1rem; border-bottom: 1px solid var(--vt-content-border-color)">                    <img :src="`https://picsum.photos/id/${p.image}/96/96`" alt="" width="48" height="48" style="border-radius: 6px" />                    <div style="flex: 1">                        <strong>{{ p.name }}</strong>                        <div style="font-size: 0.75rem; color: var(--vt-text-muted-color)">{{ p.category }}</div>                    </div>                    <Tag :value="p.stock" :severity="severity(p.stock)" />                    <span style="width: 4rem; text-align: end">${{ p.price }}</span>                </li>            </ul>        </template>        <template #grid="{ items }">            <article v-for="p in items as Product[]" :key="p.id" style="border: 1px solid var(--vt-content-border-color); border-radius: 8px; overflow: hidden">                <img :src="`https://picsum.photos/id/${p.image}/320/200`" :alt="p.name" style="display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover" />                <div style="padding: 0.75rem; display: flex; flex-direction: column; gap: 0.25rem">                    <strong>{{ p.name }}</strong>                    <small style="color: var(--vt-text-muted-color)">{{ p.category }}</small>                    <div style="display: flex; justify-content: space-between; align-items: center">                        <span>${{ p.price }}</span>                        <Tag :value="p.stock" :severity="severity(p.stock)" />                    </div>                </div>            </article>        </template>    </DataView></template>

API

Read from packages/vue/src/components/DataView/types.ts, so it says what the component actually accepts.

Props

NameTypeDescription
valueany[]The items; with `lazy`, only the current page.
layout'list' | 'grid'Which template renders the items: `list` (the default) or `grid`.
dataKeystringA field that identifies an item.
sortFieldstringSort by this field…
sortOrder1 | -1 | 0…ascending (1) or descending (-1).
paginatorboolean—
rowsnumberItems per page. Defaults to 12.
rowsPerPageOptionsnumber[]—
pageLinkSizenumber—
paginatorPosition'top' | 'bottom' | 'both'—
alwaysShowPaginatorboolean—
lazybooleanNothing is computed here: page changes are emitted (`page`) for the app to answer.
totalRecordsnumberThe total across pages when `lazy`.
loadingboolean—
emptyMessagestring—

Plus pt, dt and unstyled from BaseProps, see pass-through and unstyled mode.

Emits

EventPayloadDescription
pageevent: { page: number; first: number; rows: number; pageCount: number }—

Slots

NameSlot propsDescription
header——
footer——
list(props: { items: unknown[]; first: number })The items of the page, in the list layout.
grid(props: { items: unknown[]; first: number })The items of the page, in the grid layout. The slot's elements are the grid's cells.
empty——
loadingicon——