@bhplugin/vue3-datatable
@bhplugin/vue3-datatable
A zero-dependency Vue 3 datatable component with client/server-side pagination, sorting, filtering, row selection, and custom cell rendering.
Example
Install
NPM
npm install @bhplugin/vue3-datatable --save
Yarn
yarn add @bhplugin/vue3-datatable
Usage
<template>
<vue3-datatable :rows="rows" :columns="cols" :sortable="true" :columnFilter="true"> </vue3-datatable>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Vue3Datatable from "@bhplugin/vue3-datatable";
import type { IColumnDefinition } from "@bhplugin/vue3-datatable";
import "@bhplugin/vue3-datatable/dist/style.css";
const cols = ref<IColumnDefinition[]>([
{ field: "id", title: "ID", isUnique: true, type: "number", filter: false },
{ field: "name", title: "Name" },
{ field: "email", title: "Email" },
{ field: "age", title: "Age", type: "number" },
{ field: "dob", title: "Date of Birth", type: "date" },
{ field: "isActive", title: "Active", type: "bool" },
{ field: "address.city", title: "City" },
]);
const rows = ref<Array<Record<string, unknown>>>([
{ id: 1, name: "John Doe", email: "john@example.com", age: 28, dob: "1997-05-15", isActive: true, address: { city: "New York" } },
{ id: 2, name: "Jane Smith", email: "jane@example.com", age: 34, dob: "1991-11-22", isActive: false, address: { city: "London" } },
// ...
]);
</script>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| columns (required) | IColumnDefinition[] |
[] |
Table column definitions |
| rows (required) | Record[] |
[] |
Table row data |
| isServerMode | boolean |
false |
Enable server-side mode (disables client-side sort/filter/pagination) |
| totalRows | number |
0 |
Total row count (required in server mode) |
| skin | string |
"bh-table-striped bh-table-hover" |
Table skin classes: bh-table-striped, bh-table-hover, bh-table-bordered, bh-table-compact |
| loading | boolean |
false |
Show loading overlay/skeleton |
| hasCheckbox | boolean |
false |
Show checkbox column for row selection |
| search | string |
"" |
Global search string |
| page | number |
1 |
Current page (1-based) |
| pageSize | number |
10 |
Rows per page |
| pageSizeOptions | number[] |
[10, 20, 30, 50, 100] |
Page size dropdown options |
| showPageSize | boolean |
true |
Show page size dropdown |
| rowClass | string | Function |
"" |
Custom row class (string or (row) => string) |
| cellClass | string | Function |
"" |
Custom cell class (string or (row) => string) |
| sortable | boolean |
false |
Enable column sorting |
| sortColumn | string |
"" |
Initial sort column field |
| sortDirection | 'asc' | 'desc' |
"asc" |
Initial sort direction |
| columnFilter | boolean |
false |
Enable per-column filter inputs |
| columnFilterLang | Record<string, string> |
null |
i18n labels for filter conditions (see below) |
| pagination | boolean |
true |
Show pagination |
| showNumbers | boolean |
true |
Show page number buttons |
| showNumbersCount | number |
5 |
Max visible page number buttons |
| showFirstPage | boolean |
true |
Show first page button |
| showLastPage | boolean |
true |
Show last page button |
| paginationInfo | string |
"Showing {0} to {1} of {2} entries" |
Pagination info template ({0} = start, {1} = end, {2} = total) |
| noDataContent | string |
"No data available" |
Empty state text |
| skeletonRowCount | number |
10 |
Number of skeleton rows while loading |
| stickyHeader | boolean |
false |
Sticky table header |
| height | string |
"500px" |
Scrollable height (only with stickyHeader) |
| stickyFirstColumn | boolean |
false |
Sticky first column |
| cloneHeaderInFooter | boolean |
false |
Clone header as footer row |
| selectRowOnClick | boolean |
false |
Toggle row selection on row click |
columnFilterLang keys
{
no_filter: 'No filter',
contain: 'Contain', not_contain: 'Not contain',
equal: 'Equal', not_equal: 'Not equal',
start_with: 'Starts with', end_with: 'Ends with',
greater_than: 'Greater than', greater_than_equal: 'Greater than or equal',
less_than: 'Less than', less_than_equal: 'Less than or equal',
is_null: 'Is null', is_not_null: 'Not null',
all: 'All', true: 'True', false: 'False' // boolean column filter labels
}
Column Definition
| Prop | Type | Default | Description |
|---|---|---|---|
| isUnique | boolean |
false |
Mark as unique row identifier (used for selection keys) |
| field | string |
"" |
Data field path (supports dot notation: address.city) |
| title | string |
"" |
Column header text |
| value | string |
"" |
Initial filter value |
| condition | IFilterCondition |
"" |
Default filter condition (contain for string, equal for number/date, empty for bool) |
| type | string |
"string" |
Column type: string, number, date, bool |
| width | string |
"" |
Column width (e.g., "200px") |
| minWidth | string |
"" |
Minimum column width |
| maxWidth | string |
"" |
Maximum column width |
| hide | boolean |
false |
Hide column from rendering |
| filter | boolean |
true |
Enable column filter |
| search | boolean |
true |
Include in global search |
| sort | boolean |
true |
Enable sorting |
| html | boolean |
false |
Column contains raw HTML |
| cellRenderer | Function |
- | Custom cell renderer: (row) => '<strong>html</strong>' (sanitized automatically) |
| headerClass | string |
"" |
Custom header cell class |
| cellClass | string |
"" |
Custom body cell class |
Events
| Event | Payload | Description |
|---|---|---|
| changeServer | IServerChangeResponse |
Server mode only — aggregate event with full state (page, sort, search, filters, change_type) |
| pageChange | number |
User clicked pagination button (silent on programmatic resets) |
| pageSizeChange | number |
Page size dropdown changed |
| sortChange | ISortChangeResponse |
Column sort applied (does NOT reset page) |
| filterChange | IColumnDefinition[] |
Column filter value or condition changed |
| searchChange | string |
Global search prop changed |
| rowSelect | Record[] |
Row selection changed (user interaction only) |
| rowClick | Record |
Row single click |
| rowDBClick | Record |
Row double click |
| reset | - | reset() called — only event during reset, all others suppressed |
Event rules
- Sort does not reset page
- Filter/search/pagesize resets to page 1 but only emits the specific event (not
pageChange) pageChangefires only from explicit user pagination clicks- During reset, only
reset(+changeServerin server mode) emits — all other events suppressed
Methods
| Method | Description |
|---|---|
| reset() | Reset all state (selection, filters, search, sort, page) |
| getFilteredRows() | Returns all filtered rows |
| getVisibleRows() | Returns current page visible rows |
| getColumnFilters() | Returns column definitions with current filter state |
| getSelectedRows() | Returns all selected rows |
| clearSelectedRows() | Deselect all rows |
| selectRow(index) | Select row by index |
| unselectRow(index) | Deselect row by index |
| isRowSelected(index) | Check if row is selected |
Slots
Custom cell rendering (named by column field)
<vue3-datatable :rows="rows" :columns="cols">
<template #name="{ value }">
<strong>{{ value.name }}</strong>
</template>
</vue3-datatable>
Pagination arrow slots
<template #firstArrow> « </template>
<template #previousArrow> ‹ </template>
<template #nextArrow> › </template>
<template #lastArrow> » </template>
Empty state slot
<template #noData>
<div>No records found.</div>
</template>
Server Mode Example
<vue3-datatable
:rows="rows"
:columns="cols"
:loading="loading"
:totalRows="totalRows"
:isServerMode="true"
:pageSize="10"
:sortable="true"
:columnFilter="true"
@page-change="onPageChange"
@page-size-change="onPageSizeChange"
@sort-change="onSortChange"
@filter-change="onFilterChange"
@search-change="onSearchChange"
/>
Changelogs
License
@bhplugin/vue3-datatable is open-sourced software licensed under the MIT license.
Our other plugins
Angular Datatable - @bhplugin/ng-datatable
Support
Related Packages
@dolusoft/query-table
A thin Vue 3 table for server-side data: it renders rows and emits sort, filter,...
1,825
1
Version History
| Version | Released | License |
|---|---|---|
| 3.0.0 | MIT | |
| 2.0.2 | MIT | |
| 2.0.1 | MIT | |
| 2.0.0 | MIT | |
| 1.1.4 | MIT | |
| 1.1.3 | MIT | |
| 1.1.2 | MIT | |
| 1.1.1 | MIT | |
| 1.1.0 | MIT | |
| 1.0.3 | MIT | |
| 1.0.2 | MIT | |
| 1.0.1 | MIT | |
| 1.0.0 | MIT | |
| 0.2.0 | MIT | |
| 0.1.18 | MIT | |
| 0.1.17 | MIT | |
| 0.1.16 | MIT | |
| 0.1.15 | MIT | |
| 0.1.14 | MIT | |
| 0.1.13 | MIT | |
| 0.1.12 | MIT | |
| 0.1.11 | MIT | |
| 0.1.10 | MIT | |
| 0.1.9 | MIT | |
| 0.1.8 | MIT | |
| 0.1.7 | MIT | |
| 0.1.6 | MIT | |
| 0.1.5 | MIT | |
| 0.1.4 | MIT | |
| 0.1.3 | MIT |
Showing the latest 30 of 33. See every release on npm