Vue Material Component Framework implementing Google's Material Design specification with comprehensive UI components, theming system, and accessibility features.
—
Components for displaying and managing data in various formats including tables, lists, and hierarchical structures.
Feature-rich data table component with sorting, filtering, pagination, and selection capabilities.
/**
* Advanced data table with server-side and client-side data management
*/
const VDataTable: Component;
interface DataTableProps {
/** Array of data items to display */
items?: any[];
/** Array of header configuration objects */
headers?: DataTableHeader[];
/** Current page number (1-based) */
page?: number;
/** Number of items per page */
itemsPerPage?: number;
/** Total number of items for server-side pagination */
itemsLength?: number;
/** Array of sort configuration objects */
sortBy?: DataTableSortItem[];
/** Whether multiple columns can be sorted */
multiSort?: boolean;
/** Item selection strategy */
selectStrategy?: SelectStrategy;
/** Array of selected item keys */
modelValue?: any[];
/** Search query string for filtering */
search?: string;
/** Custom filter function */
customFilter?: FilterFunction;
/** Whether to show select checkboxes */
showSelect?: boolean;
/** Whether to show expand icons */
showExpand?: boolean;
/** Item value key for identification */
itemValue?: string | ((item: any) => any);
/** Item title key for display */
itemTitle?: string | ((item: any) => any);
/** Return object format for items */
returnObject?: boolean;
/** Table density setting */
density?: 'default' | 'comfortable' | 'compact';
/** Fixed header while scrolling */
fixedHeader?: boolean;
/** Fixed footer while scrolling */
fixedFooter?: boolean;
/** Table height for virtual scrolling */
height?: string | number;
/** Whether table content is loading */
loading?: boolean;
/** Loading text to display */
loadingText?: string;
/** Text when no data available */
noDataText?: string;
/** Hide default footer */
hideDefaultFooter?: boolean;
/** Hide default header */
hideDefaultHeader?: boolean;
/** Disable sorting functionality */
disableSort?: boolean;
/** Make rows hoverable */
hover?: boolean;
/** Custom row props function */
rowProps?: DataTableRowPropsFunction;
/** Custom cell props function */
cellProps?: DataTableCellPropsFunction;
}
interface DataTableHeader {
/** Unique key for the column */
key: string;
/** Column title text */
title?: string;
/** Value path for nested objects */
value?: string;
/** Column span count */
colspan?: number;
/** Row span count */
rowspan?: number;
/** Whether column is sortable */
sortable?: boolean;
/** Custom sort function */
sort?: DataTableCompareFunction;
/** Text alignment */
align?: 'start' | 'center' | 'end';
/** Column width */
width?: string | number;
/** Minimum column width */
minWidth?: string | number;
/** Maximum column width */
maxWidth?: string | number;
/** Whether column is fixed */
fixed?: boolean;
/** Filter function for this column */
filter?: FilterFunction;
}
interface DataTableSortItem {
/** Column key to sort by */
key: string;
/** Sort order */
order?: 'asc' | 'desc';
}
type DataTableCompareFunction<T = any> = (a: T, b: T) => number;
type DataTableRowPropsFunction = (data: { item: any; index: number }) => Record<string, any>;
type DataTableCellPropsFunction = (data: { item: any; column: DataTableHeader; index: number }) => Record<string, any>;
// Events
interface DataTableEvents {
'update:modelValue': (value: any[]) => void;
'update:page': (page: number) => void;
'update:itemsPerPage': (itemsPerPage: number) => void;
'update:sortBy': (sortBy: DataTableSortItem[]) => void;
'update:expanded': (expanded: any[]) => void;
'click:row': (event: Event, data: { item: any; index: number }) => void;
'contextmenu:row': (event: Event, data: { item: any; index: number }) => void;
}Usage Examples:
<template>
<!-- Basic data table -->
<v-data-table
:items="items"
:headers="headers"
item-value="id"
/>
<!-- With selection and pagination -->
<v-data-table
v-model="selected"
:items="items"
:headers="headers"
:items-per-page="10"
show-select
item-value="id"
@click:row="handleRowClick"
/>
<!-- Server-side data table -->
<v-data-table
:items="serverItems"
:headers="headers"
:items-length="totalItems"
:loading="loading"
@update:page="loadPage"
@update:items-per-page="updateItemsPerPage"
@update:sort-by="updateSort"
/>
</template>
<script setup>
const headers = [
{ title: 'Name', key: 'name', sortable: true },
{ title: 'Email', key: 'email', sortable: true },
{ title: 'Role', key: 'role', sortable: false },
{ title: 'Actions', key: 'actions', sortable: false },
];
const items = ref([
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
]);
const selected = ref([]);
</script>Flexible data display component with customizable item templates and built-in pagination.
/**
* Flexible data iterator with custom item templates
*/
const VDataIterator: Component;
interface DataIteratorProps {
/** Array of data items */
items?: any[];
/** Current page number */
page?: number;
/** Items per page */
itemsPerPage?: number;
/** Total items count for server-side */
itemsLength?: number;
/** Sort configuration */
sortBy?: DataTableSortItem[];
/** Search query */
search?: string;
/** Custom filter function */
customFilter?: FilterFunction;
/** Item value key */
itemValue?: string | ((item: any) => any);
/** Return object format */
returnObject?: boolean;
/** Loading state */
loading?: boolean;
/** No data text */
noDataText?: string;
}
// Events
interface DataIteratorEvents {
'update:page': (page: number) => void;
'update:itemsPerPage': (itemsPerPage: number) => void;
'update:sortBy': (sortBy: DataTableSortItem[]) => void;
}Usage Examples:
<template>
<v-data-iterator
:items="items"
:items-per-page="6"
>
<template #default="{ items }">
<v-row>
<v-col
v-for="item in items"
:key="item.id"
cols="12"
sm="6"
md="4"
>
<v-card>
<v-card-title>{{ item.name }}</v-card-title>
<v-card-text>{{ item.description }}</v-card-text>
</v-card>
</v-col>
</v-row>
</template>
</v-data-iterator>
</template>Versatile list component for displaying items with various layouts and interactive features.
/**
* List component for displaying collections of items
*/
const VList: Component;
interface ListProps {
/** List items array */
items?: any[];
/** Selected item values */
modelValue?: any;
/** Item value key */
itemValue?: string | ((item: any) => any);
/** Item title key */
itemTitle?: string | ((item: any) => any);
/** Item props key */
itemProps?: string | ((item: any) => any);
/** Item children key for nested lists */
itemChildren?: string | ((item: any) => any);
/** Return object format */
returnObject?: boolean;
/** List density */
density?: 'default' | 'comfortable' | 'compact';
/** Navigation style */
nav?: boolean;
/** Selection strategy */
selectStrategy?: SelectStrategy;
/** Open strategy for nested items */
openStrategy?: OpenStrategy;
/** Activation strategy */
activateStrategy?: ActiveStrategy;
/** List background color */
bgColor?: string;
/** Whether list items are clickable */
itemType?: 'item' | 'divider' | 'subheader';
/** Disable list interactions */
disabled?: boolean;
/** Mandatory selection */
mandatory?: boolean;
/** Multiple selection */
multiple?: boolean;
}
// Events
interface ListEvents {
'update:modelValue': (value: any) => void;
'update:opened': (opened: any[]) => void;
'click:open': (data: { id: any; value: boolean }) => void;
'click:select': (data: { id: any; value: boolean }) => void;
'click:activate': (data: { id: any; value: boolean }) => void;
}Usage Examples:
<template>
<!-- Basic list -->
<v-list>
<v-list-item
v-for="item in items"
:key="item.id"
:title="item.title"
:subtitle="item.subtitle"
@click="handleClick(item)"
/>
</v-list>
<!-- Navigation list -->
<v-list nav density="compact">
<v-list-item
v-for="item in navItems"
:key="item.id"
:to="item.to"
:prepend-icon="item.icon"
:title="item.title"
/>
</v-list>
<!-- Selection list -->
<v-list
v-model="selected"
select-strategy="multiple-leaf"
>
<v-list-item
v-for="item in selectableItems"
:key="item.id"
:value="item.id"
:title="item.title"
/>
</v-list>
</template>Simple HTML table wrapper with Vuetify styling and responsive features.
/**
* Simple table wrapper component
*/
const VTable: Component;
interface TableProps {
/** Table density */
density?: 'default' | 'comfortable' | 'compact';
/** Fixed header */
fixedHeader?: boolean;
/** Fixed footer */
fixedFooter?: boolean;
/** Table height */
height?: string | number;
/** Hover effect on rows */
hover?: boolean;
/** Theme variant */
theme?: string;
}Usage Examples:
<template>
<v-table density="compact" hover>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.email }}</td>
<td>{{ item.role }}</td>
</tr>
</tbody>
</v-table>
</template>Hierarchical tree view component with expandable nodes and selection capabilities.
/**
* Tree view component for hierarchical data
*/
const VTreeview: Component;
interface TreeviewProps {
/** Tree items array */
items?: any[];
/** Selected item values */
modelValue?: any[];
/** Opened/expanded nodes */
opened?: any[];
/** Activated item */
activated?: any[];
/** Item value key */
itemValue?: string | ((item: any) => any);
/** Item title key */
itemTitle?: string | ((item: any) => any);
/** Item children key */
itemChildren?: string | ((item: any) => any);
/** Item props key */
itemProps?: string | ((item: any) => any);
/** Return object format */
returnObject?: boolean;
/** Selection strategy */
selectStrategy?: SelectStrategy;
/** Open strategy */
openStrategy?: OpenStrategy;
/** Activation strategy */
activateStrategy?: ActiveStrategy;
/** Tree density */
density?: 'default' | 'comfortable' | 'compact';
/** Loading state */
loading?: boolean;
/** Load children function for lazy loading */
loadChildren?: (item: any) => Promise<any[]>;
}
// Events
interface TreeviewEvents {
'update:modelValue': (value: any[]) => void;
'update:opened': (opened: any[]) => void;
'update:activated': (activated: any[]) => void;
'click:open': (data: { id: any; value: boolean; path: any[] }) => void;
'click:select': (data: { id: any; value: boolean; path: any[] }) => void;
'click:activate': (data: { id: any; value: boolean; path: any[] }) => void;
}Usage Examples:
<template>
<!-- Basic tree -->
<v-treeview
:items="treeItems"
item-title="name"
item-value="id"
item-children="children"
/>
<!-- Selectable tree -->
<v-treeview
v-model="selected"
:items="treeItems"
select-strategy="leaf"
open-strategy="multiple"
item-title="name"
item-value="id"
item-children="children"
/>
<!-- Lazy loading tree -->
<v-treeview
:items="lazyItems"
:load-children="loadChildren"
item-title="name"
item-value="id"
/>
</template>
<script setup>
const treeItems = ref([
{
id: 1,
name: 'Folder 1',
children: [
{ id: 2, name: 'File 1.1' },
{ id: 3, name: 'File 1.2' },
]
},
{
id: 4,
name: 'Folder 2',
children: [
{ id: 5, name: 'File 2.1' },
]
},
]);
const loadChildren = async (item) => {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
return [
{ id: `${item.id}-1`, name: `Child of ${item.name}` }
];
};
</script>Timeline component for displaying chronological events and milestones.
/**
* Timeline component for chronological event display
*/
const VTimeline: Component;
interface TimelineProps {
/** Timeline items */
items?: any[];
/** Timeline direction */
direction?: 'horizontal' | 'vertical';
/** Alignment of timeline */
align?: 'start' | 'center' | 'end';
/** Timeline side for vertical layout */
side?: 'start' | 'end';
/** Line thickness */
lineThickness?: string | number;
/** Timeline density */
density?: 'default' | 'comfortable' | 'compact';
/** Reverse order */
reverse?: boolean;
/** Truncate line at edges */
truncateLine?: 'start' | 'end' | 'both';
}Usage Examples:
<template>
<v-timeline direction="vertical" align="start">
<v-timeline-item
v-for="item in timelineItems"
:key="item.id"
:dot-color="item.color"
size="small"
>
<template #icon>
<v-icon>{{ item.icon }}</v-icon>
</template>
<v-card>
<v-card-title>{{ item.title }}</v-card-title>
<v-card-subtitle>{{ item.time }}</v-card-subtitle>
<v-card-text>{{ item.description }}</v-card-text>
</v-card>
</v-timeline-item>
</v-timeline>
</template>
<script setup>
const timelineItems = [
{
id: 1,
title: 'Project Started',
time: '9:00 AM',
description: 'Initial project setup and planning',
icon: 'mdi-play-circle',
color: 'success'
},
{
id: 2,
title: 'Development Phase',
time: '10:30 AM',
description: 'Core functionality implementation',
icon: 'mdi-code-tags',
color: 'primary'
}
];
</script>Virtual scrolling component for efficiently rendering large lists.
/**
* Virtual scrolling container for large datasets
*/
const VVirtualScroll: Component;
interface VirtualScrollProps {
/** Array of items to render */
items?: any[];
/** Height of each item */
itemHeight?: number | string | ((index: number) => number);
/** Container height */
height?: number | string;
/** Container max height */
maxHeight?: number | string;
/** Bench (buffer) size for rendering */
bench?: number;
/** Item component to render */
component?: string | Component;
/** Item props function */
itemProps?: (data: { item: any; index: number }) => Record<string, any>;
}
// Events
interface VirtualScrollEvents {
'update:modelValue': (value: any[]) => void;
}Usage Examples:
<template>
<!-- Basic virtual scroll -->
<v-virtual-scroll
:items="largeDataset"
:item-height="48"
height="400"
>
<template #default="{ item, index }">
<v-list-item :title="item.name" :subtitle="item.description" />
</template>
</v-virtual-scroll>
<!-- Dynamic item heights -->
<v-virtual-scroll
:items="variableItems"
:item-height="(index) => getItemHeight(index)"
height="400"
>
<template #default="{ item }">
<v-card class="ma-2">
<v-card-text>{{ item.content }}</v-card-text>
</v-card>
</template>
</v-virtual-scroll>
</template>
<script setup>
const largeDataset = ref(
Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i}`,
description: `Description for item ${i}`
}))
);
const getItemHeight = (index) => {
return index % 3 === 0 ? 80 : 48; // Variable heights
};
</script>Infinite scroll component for loading data incrementally as user scrolls.
/**
* Infinite scroll loading component
*/
const VInfiniteScroll: Component;
interface InfiniteScrollProps {
/** Loading state */
loading?: boolean;
/** Whether there are more items to load */
hasMore?: boolean;
/** Load more function */
onLoad?: (options: { done: (status?: 'ok' | 'error' | 'empty') => void }) => void;
/** Scroll direction */
direction?: 'vertical' | 'horizontal';
/** Distance from edge to trigger load */
margin?: number;
/** Container height */
height?: number | string;
/** Maximum height */
maxHeight?: number | string;
/** Loading text */
loadingText?: string;
/** Empty state text */
emptyText?: string;
/** Error state text */
errorText?: string;
/** Color theme */
color?: string;
}
// Events
interface InfiniteScrollEvents {
'load': (options: { done: (status?: string) => void }) => void;
}Usage Examples:
<template>
<v-infinite-scroll
@load="loadMore"
height="400"
:loading="loading"
>
<v-list>
<v-list-item
v-for="item in items"
:key="item.id"
:title="item.title"
:subtitle="item.subtitle"
/>
</v-list>
</v-infinite-scroll>
</template>
<script setup>
const items = ref([]);
const loading = ref(false);
const page = ref(1);
const loadMore = async ({ done }) => {
loading.value = true;
try {
const response = await fetchItems(page.value);
items.value.push(...response.data);
page.value++;
if (response.hasMore) {
done('ok');
} else {
done('empty'); // No more items
}
} catch (error) {
done('error');
} finally {
loading.value = false;
}
};
</script>// Filter and comparison types
type FilterFunction = (value: any, query: string, item: any) => boolean;
type FilterMatch = boolean | number | [number, number];
// Selection strategy types
type SelectStrategy =
| 'single-leaf'
| 'leaf'
| 'independent'
| 'single-independent'
| 'multiple-leaf'
| 'multiple-independent';
type OpenStrategy = 'single' | 'multiple' | 'list';
type ActiveStrategy = 'single-leaf' | 'leaf' | 'independent' | 'single-independent';
// Internal item representation
interface InternalItem {
type: 'item' | 'divider' | 'subheader';
title: string;
value: any;
props: Record<string, any>;
children?: InternalItem[];
raw: any;
}Install with Tessl CLI
npx tessl i tessl/npm-vuetify