DataTable displays data in tabular format.
Name | Country | Agent | Date | Balance | Status | Activity |
---|
import { DataTable } from 'primereact/datatable';
<script src="https://unpkg.com/primereact/core/core.min.js"></script>
<script src="https://unpkg.com/primereact/column/column.min.js"></script>
<script src="https://unpkg.com/primereact/datatable/datatable.min.js"></script>
DataTable requires a value as an array of objects and columns defined with Column component. Throughout the samples, a product interface having code, name, description, image, category, quantity, price, inventoryStatus and rating properties is used to define an object to be displayed by the datatable. Products are loaded by a CustomerService that connects to a server to fetch the products. Note that this is only for demo purposes, DataTable does not have any restrictions on how data is provided.
export default class ProductService {
getProductsSmall() {
return fetch('data/products-small.json').then(res => res.json()).then(d => d.data);
}
getProducts() {
return fetch('data/products.json').then(res => res.json()).then(d => d.data);
}
getProductsWithOrdersSmall() {
return fetch('data/products-orders-small.json').then(res => res.json()).then(d => d.data);
}
}
Following sample datatable has 4 columns and retrieves the data from a service on componentDidMount.
export const DataTableDemo = () => {
const [products, setProducts] = useState([])
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
return (
<DataTable value={products}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
);
}
Dynamic columns are also possible by creating the column component dynamically.
export const DataTableDemo = () => {
const [products, setProducts] = useState([]);
const columns = [
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
];
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
const dynamicColumns = columns.map((col,i) => {
return <Column key={col.field} field={col.field} header={col.header} />;
});
return (
<DataTable value={products}>
{dynamicColumns}
</DataTable>
);
}
Column component defines various options to specify corresponding features.
Name | Type | Default | Description |
---|---|---|---|
columnKey | string | null | Identifier of a column if field property is not defined. Only utilized by reorderableColumns feature at the moment. |
field | string | null | Property of a row data. |
sortField | string | null | Property of a row data used for sorting, defaults to field. |
filterField | string | null | Property of a row data used for filtering, defaults to field. |
exportField | string | null | Property of a row data used for exporting, defaults to field. |
header | any | null | Header content of the column. |
body | any | null | Body content of the column. |
bodyStyle | object | null | Inline style of the body. |
bodyClassName | string | function | null | Style class of the body. If using a function must return a string. |
footer | any | null | Footer content of the column. |
sortable | boolean | false | Defines if a column is sortable. |
sortFunction | function | null | Sort function for custom sorting. |
sortableDisabled | boolean | false | When enabled, the data of columns with this property cannot be sorted or changed by the user. |
dataType | string | null | Depending on the dataType of the column, suitable match modes are displayed. |
filter | boolean | false | Defines if a column can be filtered. |
filterMatchMode | string | null | Defines filterMatchMode; "startsWith", "contains", "endsWith", "equals", "notEquals", "in", "lt", "lte", "gt", "gte" and "custom". |
filterType | string | text | Type of the filter input field. |
filterPlaceholder | string | null | Defines placeholder of the input fields. |
filterMaxlength | number | null | Specifies the maximum number of characters allowed in the filter element. |
filterElement | object | null | Element for custom filtering. |
filterFunction | function | null | Custom filter function. |
excludeGlobalFilter | boolean | false | Whether to exclude from global filtering or not. |
filterHeaderStyle | object | null | Inline style of the filter header. |
filterHeaderClassName | string | null | Style class of the filter header. |
showFilterMenu | boolean | true | Whether to display the filter overlay. |
showFilterOperator | boolean | true | When enabled, match all and match any operator selector is displayed. |
showClearButton | boolean | true | Displays a button to clear the column filtering. |
showApplyButton | boolean | true | Displays a button to apply the column filtering. |
showFilterMatchModes | boolean | true | Whether to show the match modes selector. |
showFilterMenuOptions | boolean | true | Whether to show the match modes selector and match operator selector. |
showAddButton | boolean | true | When enabled, a button is displayed to add more rules. |
filterMatchModeOptions | array | null | An array of label-value pairs to override the global match mode options. |
maxConstraints | number | 2 | Maximum number of constraints for a column filter. |
filterMenuClassName | string | null | Style class of the column filter overlay. |
filterMenuStyle | object | null | Inline style of the column filter overlay. |
align | string | null | Aligns the content of the column, valid values are left, right and center. |
alignHeader | string | null | Aligns the header of the column, valid values are left, right and center. |
alignFrozen | string | left | Position of a frozen column, valid values are left and right. |
hidden | boolean | false | Whether the column is rendered. |
onFilterClear | function | null | Callback to invoke when the filter meta is cleared. |
onFilterApplyClick | function | null | Callback to invoke when the apply button is clicked. |
onFilterMatchModeChange | function | null | Callback to invoke when the match mode option is changed. |
onFilterOperatorChange | function | null | Callback to invoke when the filter operator option is changed. |
onFilterConstraintAdd | function | null | Callback to invoke when a new constraint is added. |
onFilterConstraintRemove | function | null | Callback to invoke when a constraint is removed. |
filterClear | any | null | Template of clear element in menu. |
filterApply | any | null | Template of apply element in menu. |
filterHeader | any | null | Template of header element in menu. |
filterFooter | any | null | Template of footer element in menu. |
style | object | null | Inline style of the column. |
className | string | null | Style class of the column. |
headerStyle | object | null | Inline style of the header. |
headerClassName | string | null | Style class of the header. |
headerTooltip | any | null | Content of the header tooltip. |
headerTooltipOptions | object | null | Configuration of the header tooltip, refer to the tooltip documentation for more information. |
footerStyle | object | null | Inline style of the footer. |
footerClassName | string | null | Style class of the footer. |
expander | boolean | false | Displays an icon to toggle row expansion. |
frozen | boolean | false | Whether the column is fixed in horizontal scrolling or not. |
selectionMode | string | null | Defines column based selection mode, options are "single" and "multiple". |
colSpan | number | null | Number of columns to span for grouping. |
rowSpan | number | null | Number of rows to span for grouping. |
editor | function | null | Function to provide the cell editor input. |
cellEditValidator | function | null | Validator function to validate the cell input value. |
cellEditValidatorEvent | string | click | Event to trigger the validation, possible values are "click" and "blur". |
onBeforeCellEditShow | function | null | Callback to invoke before the cell editor is shown. |
onBeforeCellEditHide | function | null | Callback to invoke before the cell editor is hidden. |
onCellEditInit | function | null | Callback to invoke when cell edit is initiated. |
onCellEditComplete | function | null | Callback to execute when editor is submitted. |
onCellEditCancel | function | null | Callback to execute when editor is cancelled. |
rowReorder | boolean | false | Whether this column displays an icon to reorder the rows. |
rowReorderIcon | string | pi pi-bars | Icon of the drag handle to reorder rows. |
rowEditor | boolean | false | Displays icons to edit row. |
exportable | boolean | true | Defines whether the column is exported or not. |
reorderable | boolean | null | Used to defined reorderableColumns per column when reorderableColumns of table is enabled, defaults to value of reorderableColumns. |
resizeable | boolean | null | Used to defined resizeableColumns per column when resizeableColumns of table is enabled, defaults to value of resizeableColumns. |
Default table-layout is fixed meaning the cell widths do not depend on their content. If you require cells to scale based on their contents set autoLayout property to true. Note that Scrollable and/or Resizable tables do not support auto layout due to technical limitations.
Field data of a corresponding row is displayed as the cell content by default, this can be customized using templating where current row data and column properties are passed to the body template. On the other hand, header and footer properties of a column are used to define the content of these sections by accepting either simple string values or JSX for advanced content. Similarly DataTable itself also provides header and footer properties for the main header and footer of the table.
export const DataTableTemplatingDemo = () => {
const [products, setProducts] = useState([])
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, []);
const formatCurrency = (value) => {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
const imageBodyTemplate = (rowData) => {
return <img src={`images/product/${rowData.image}`} alt={rowData.image} className="product-image" />;
}
const priceBodyTemplate = (rowData) => {
return formatCurrency(rowData.price);
}
const ratingBodyTemplate = (rowData) => {
return <Rating value={rowData.rating} readonly cancel={false} />;
}
const statusBodyTemplate = (rowData) => {
return <span className={`product-badge status-${rowData.inventoryStatus.toLowerCase()}`}>{rowData.inventoryStatus}</span>;
}
const header = (
<div className="table-header">
Products
<Button icon="pi pi-refresh" />
</div>
);
const footer = `In total there are ${products ? products.length : 0} products.`;
return (
<DataTable value={products} header={header} footer={footer}>
<Column field="name" header="Name"></Column>
<Column header="Image" body={imageBodyTemplate}></Column>
<Column field="price" header="Price" body={priceBodyTemplate}></Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews" body={ratingBodyTemplate}></Column>
<Column header="Status" body={statusBodyTemplate}></Column>
</DataTable>
);
}
In addition to the regular table, a smal and a large version are available with different paddings.
<DataTable value={products} header="Small Table" size="small">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
<DataTable value={products} header="Small Table" size="normal">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
<DataTable value={products} header="Small Table" size="large">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
Columns can be grouped at header and footer sections by defining a ColumnGroup component as the headerColumnGroup and footerColumnGroup properties.
import React, { Component } from 'react';
import {DataTable} from 'primereact/datatable';
import {Column} from 'primereact/column';
import {ColumnGroup} from 'primereact/columngroup';
import {Row} from 'primereact/row';
export const DataTableColGroupDemo = () => {
const sales = [
{product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342},
{product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122},
{product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500},
{product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323},
{product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332},
{product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005},
{product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214},
{product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322},
{product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232},
{product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533}
];
const lastYearSaleBodyTemplate = (rowData) => {
return `${rowData.lastYearSale}%`;
}
const thisYearSaleBodyTemplate = (rowData) => {
return `${rowData.thisYearSale}%`;
}
const lastYearProfitBodyTemplate = (rowData) => {
return `${formatCurrency(rowData.lastYearProfit)}`;
}
const thisYearProfitBodyTemplate = (rowData) => {
return `${formatCurrency(rowData.thisYearProfit)}`;
}
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
const lastYearTotal = () => {
let total = 0;
for(let sale of sales) {
total += sale.lastYearProfit;
}
return formatCurrency(total);
}
const thisYearTotal = () => {
let total = 0;
for(let sale of sales) {
total += sale.thisYearProfit;
}
return formatCurrency(total);
}
let headerGroup = <ColumnGroup>
<Row>
<Column header="Product" rowSpan={3} />
<Column header="Sale Rate" colSpan={4} />
</Row>
<Row>
<Column header="Sales" colSpan={2} />
<Column header="Profits" colSpan={2} />
</Row>
<Row>
<Column header="Last Year" sortable field="lastYearSale"/>
<Column header="This Year" sortable field="thisYearSale"/>
<Column header="Last Year" sortable field="lastYearProfit"/>
<Column header="This Year" sortable field="thisYearProfit"/>
</Row>
</ColumnGroup>;
let footerGroup = <ColumnGroup>
<Row>
<Column footer="Totals:" colSpan={3} footerStyle={{textAlign: 'right'}}/>
<Column footer={lastYearTotal} />
<Column footer={thisYearTotal} />
</Row>
</ColumnGroup>;
return (
<DataTable value={sales} headerColumnGroup={headerGroup} footerColumnGroup={footerGroup}>
<Column field="product" />
<Column field="lastYearSale" body={lastYearSaleBodyTemplate} />
<Column field="thisYearSale" body={thisYearSaleBodyTemplate} />
<Column field="lastYearProfit" body={lastYearProfitBodyTemplate} />
<Column field="thisYearProfit" body={thisYearProfitBodyTemplate} />
</DataTable>
);
}
When using sorting with column groups, define sort properties like sortable at columns inside column groups not at the direct children of DataTable component.
Pagination is enabled by setting paginator property to true, rows property defines the number of rows per page and optionally pageLinks specify the the number of page links to display. See paginator component for more information about further customization options such as paginator template.
Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties need to be defined to control the paginator state.
export const DataTablePaginatorDemo = () => {
const [products, setProducts] = useState([]);
const [first, setFirst] = useState(0);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
return (
<DataTable value={products} paginator rows={10} first={first} onPage={(e) => setFirst(e.first)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
);
}
In uncontrolled mode, only paginator and rows need to be enabled. Index of the first record can be still be provided using the first property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the paginator state, prefer to use the component as controlled.
export const DataTablePaginatorDemo = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
return (
<DataTable value={products} paginator rows={10}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
);
}
Elements of the paginator can be customized using the paginatorTemplate by the DataTable. Refer to the template section of the paginator documentation for further options.
<DataTable value={products} paginator rows={10} first={start}
paginatorTemplate="RowsPerPageDropdown PageLinks FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
Enabling sortable property at column component would be enough to make a column sortable. The property to use when sorting is field by default and can be customized using sortField.
<Column field="name" header="Name" sortable/>
By default sorting is executed on the clicked column only. To enable multiple field sorting, set sortMode property to "multiple" and use metakey when clicking on another column.
<DataTable value={products} sortMode="multiple">
In case you'd like to display the table as sorted per a single column by default on mount, use sortField and sortOrder properties in Controlled or Uncontrolled manner. In controlled mode, sortField, sortOrder and onSort properties need to be defined to control the sorting state.
const onSort = (e) => {
setSortField(e.sortField);
setSortOrder(e.sortOrder);
}
<DataTable value={products} sortField={sortField} sortOrder={sortOrder} onSort={onSort}>
<Column field="code" header="Code" sortable></Column>
<Column field="name" header="Name" sortable></Column>
<Column field="category" header="Category" sortable></Column>
<Column field="quantity" header="Quantity" sortable></Column>
</DataTable>
In multiple mode, use the multiSortMeta property and bind an array of SortMeta objects instead.
<DataTable value={products} multiSortMeta={multiSortMeta} onSort={(e) => setMultiSortMeta(e.multiSortMeta)}>
<Column field="code" header="Code" sortable></Column>
<Column field="name" header="Name" sortable></Column>
<Column field="category" header="Category" sortable></Column>
<Column field="quantity" header="Quantity" sortable></Column>
</DataTable>
let multiSortMeta = [];
multiSortMeta.push({field: 'code', order: 1});
multiSortMeta.push({field: 'name', order: -1});
In uncontrolled mode, no additional properties need to be enabled. Initial sort field can be still be provided using the sortField property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the sorting state, prefer to use the component as controlled.
<DataTable value={products} sortField="name" sortOrder={1}>
<Column field="code" header="Code" sortable></Column>
<Column field="name" header="Name" sortable></Column>
<Column field="category" header="Category" sortable></Column>
<Column field="quantity" header="Quantity" sortable></Column>
</DataTable>
To customize sorting algorithm, define a sortFunction that sorts the list.
<DataTable value={products} >
<Column field="code" header="Code" sortable></Column>
<Column field="name" header="Name" sortable sortFunction={mysort}></Column>
<Column field="category" header="Category" sortable></Column>
<Column field="quantity" header="Quantity" sortable></Column>
</DataTable>
const mysort = (event) => {
//event.data = Data
//event.field = Field to sort
//event.order = Sort order
//event.multiSortMeta = An array of SortMeta objects to sort the data by default in multiple sort mode.
}
Getting access to the sorted data is provided by the onValueChange callback.
<DataTable value={products} onValueChange={sortedData => console.log(sortedData)}>
<Column field="code" header="Code" sortable></Column>
<Column field="name" header="Name" sortable></Column>
<Column field="category" header="Category" sortable></Column>
<Column field="quantity" header="Quantity" sortable></Column>
</DataTable>
DataTable has advanced filtering capabilities that does the heavy lifting while providing flexible customization. Filtering has two layout alternatives defined with the filterDisplay. In row setting, filter elements are displayed in a separate row at the header section whereas in menu mode filter elements are displayed inside an overlay. The template filter gets a value, filterCallback and filterApplyCallback, use value to populate the filter with your own form components and call the filterCallback with the event of your choice like onInput, onChange, onClick. FilterCallback adds new values in hidden 'filters' state in DataTable and when filterApplyCallback is called, data is filtered. The filterApplyCallback method can be used directly if you want to filter by value directly.
const DataTableFilterDemo = () => {
const [customers, setCustomers] = useState(null);
const filters = {
'name': { value: null, matchMode: FilterMatchMode.STARTS_WITH }
}
return (
<DataTable value={customers} filters={filters}>
<Column field="name" header="Name" filter></Column>
</DataTable>
)
}
Input field is displayed in a separate header row.
<DataTable value={customers} filters={filters} filterDisplay="row">
<Column field="name" header="Name" filter></Column>
</DataTable>
Input field is displayed in an overlay.
<DataTable value={customers} filters={filters} filterDisplay="menu">
<Column field="name" header="Name" filter></Column>
</DataTable>
In "menu" display, it is possible to add more constraints to a same filter. In this case, metadata could be an array of constraints. The operator defines whether all or any of the constraints should match.
const filters = {
'name': {operator: FilterOperator.AND, constraints: [{value: null, matchMode: FilterMatchMode.STARTS_WITH}]},
}
Providing a filters with predefined values would be enough to display the table as filtered by default. This approach can also be used to clear filters progammatically.
const filters = {
'name': {operator: FilterOperator.AND, constraints: [
{value: 'Prime', matchMode: FilterMatchMode.STARTS_WITH},
{value: 'React', matchMode: FilterMatchMode.CONTAINS}
]}
}
Depending on the dataType of the column, suitable match modes are displayed. Default configuration is available at PrimeReact.filterMatchModeOptions which can be used to customize the modes globally for all tables.
PrimeReact.filterMatchModeOptions = {
text: [
FilterMatchMode.STARTS_WITH,
FilterMatchMode.CONTAINS,
FilterMatchMode.NOT_CONTAINS,
FilterMatchMode.ENDS_WITH,
FilterMatchMode.EQUALS,
FilterMatchMode.NOT_EQUALS
],
numeric: [
FilterMatchMode.EQUALS,
FilterMatchMode.NOT_EQUALS,
FilterMatchMode.LESS_THAN,
FilterMatchMode.LESS_THAN_OR_EQUAL_TO,
FilterMatchMode.GREATER_THAN,
FilterMatchMode.GREATER_THAN_OR_EQUAL_TO
],
date: [
FilterMatchMode.DATE_IS,
FilterMatchMode.DATE_IS_NOT,
FilterMatchMode.DATE_BEFORE,
FilterMatchMode.DATE_AFTER
]
}
If you need to override the match modes for a particular column use the filterMatchModeOptions property and provide an array with label-value pairs.
const matchModes = [
{label: 'Starts With', value: FilterMatchMode.STARTS_WITH},
{label: 'Contains', value: FilterMatchMode.CONTAINS},
];
...
<Column field="name" header="Name" filterMatchModeOptions={matchModes} />
Custom filtering is implemented using the FilterService, first register your filter and add it to your filterMatchModeOptions.
import {FilterService} from 'primereact/api';
FilterService.register('myfilter', (a,b) => a === b);
...
const matchModes = [
{label: 'My Filter', value: "myfilter"},
{label: 'Starts With', value: FilterMatchMode.STARTS_WITH},
{label: 'Contains', value: FilterMatchMode.CONTAINS},
]
By default, input fields are used as filter elements and this can be customized using the filterElement property of the Column that calls the filter function of the table instance by passing the value, field and the match mode.
export const DataTableCustomFilterDemo = () => {
const [products, setProducts] = useState([]);
const filters = {
'inventoryStatus': { value: null, matchMode: FilterMatchMode.EQUALS }
};
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
} ,[])
const onStatusChange = (e, options) => {
options.filterCallback(event.value);
}
let inventoryStatuses = [
{label: 'All Status', value: null},
{label: 'INSTOCK', value: 'INSTOCK'},
{label: 'LOWSTOCK', value: 'LOWSTOCK'},
{label: 'OUTOFSTOCK', value: 'OUTOFSTOCK'}
];
let statusFilter = (options) => <Dropdown style={{width: '100%'}} className="ui-column-filter"
value={options.value} options={inventoryStatuses} onChange={(e) => onStatusChange(e, options)}/>
return (
<DataTable value={products} filters={filters}>
<Column field="code" header="Code" filter></Column>
<Column field="name" header="Name" filter></Column>
<Column field="category" header="Category" filter></Column>
<Column field="inventoryStatus" header="Status" filter filterElement="statusFilter"></Column>
</DataTable>
);
}
In case you'd like to display the table as filtered by default on mount, use filters property in Controlled or Uncontrolled manner. In controlled mode, filters and onFilter properties need to be defined to control the filtering state.
export const DataTableDefaultFilteredDemo = () => {
const [products, setProducts] = useState([]);
const [filters, setFilters] = useState({
'inventoryStatus': {
value: 'INSTOCK'
});
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
} ,[])
return (
<DataTable value={products} filters={filters} onFilter={(e) => setFilters(e.filters)}>
<Column field="code" header="Code" filter></Column>
<Column field="name" header="Name" filter></Column>
<Column field="category" header="Category" filter></Column>
<Column field="inventoryStatus" header="Status" filter></Column>
</DataTable>
);
}
In uncontrolled filtering, no additional properties need to be enabled. Initial filtering can be still be provided using the filters property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the filtering state, prefer to use the component as controlled.
<DataTable value={products}>
<Column field="code" header="Code" filter></Column>
<Column field="name" header="Name" filter></Column>
<Column field="category" header="Category" filter></Column>
<Column field="inventoryStatus" header="Status" filter></Column>
</DataTable>
Getting access to the filtered data is provided by the onValueChange callback.
<DataTable value={products} onValueChange={filteredData => console.log(filteredData)}>
<Column field="code" header="Code" filter></Column>
<Column field="name" header="Name" filter></Column>
<Column field="category" header="Category" filter></Column>
<Column field="inventoryStatus" header="Status" filter></Column>
</DataTable>
DataTable provides single and multiple selection modes on click of a row or cell. Selected rows are bound to the selection property for reading and updated using onSelectionChange callback. Alternatively column based selection can be done using radio buttons or checkboxes using selectionMode of a particular column. In addition onRowSelect-onRowUnselect / onCellSelect-onCellUnselect events are provided as optional callbacks.
In single mode, selection binding is an object reference.
export const DataTableSelectionDemo = () => {
const [products, setProducts] = useState([]);
const [selectedProduct1, setSelectedProduct1] = useState(null);
const [selectedProduct2, setSelectedProduct2] = useState(null);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
return (
<>
<DataTable value={products} selectionMode="single"
selection={selectedProduct1} onSelectionChange={e => setSelectedProduct1(e.value)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
<DataTable value={products} selectionMode="single" cellSelection
selection={selectedProduct2} onSelectionChange={e => setSelectedProduct2(e.value)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
</>
);
}
In multiple mode, selection binding should be an array and multiple items can either be selected using metaKey or toggled individually depending on the value of metaKeySelection property value which is true by default. On touch enabled devices metaKeySelection is turned off automatically. Also, ShiftKey is supported for range selection. In addition, the rectangular selection can be dragged over the desired rows or cells thanks to the dragSelection property. In this way, a range of rows or cells can be selected.
export const DataTableSelectionDemo = () => {
const [products, setProducts] = useState([]);
const [selectedProducts1, setSelectedProducts1] = useState(null);
const [selectedProducts2, setSelectedProducts2] = useState(null);
const [selectedProducts3, setSelectedProducts3] = useState(null);
const [selectedProducts4, setSelectedProducts4] = useState(null);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, []);
return (
<>
<DataTable value={products} selectionMode="multiple"
selection={selectedProducts1} onSelectionChange={e => setSelectedProducts1(e.value)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
<DataTable value={products} selectionMode="multiple"
selection={selectedProducts2} onSelectionChange={e => setSelectedProducts2(e.value)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
<DataTable value={products} selectionMode="multiple" cellSelection
selection={selectedProducts3} onSelectionChange={e => setSelectedProducts3(e.value)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
<DataTable value={products} selectionMode="multiple" cellSelection dragSelection
selection={selectedProducts4} onSelectionChange={e => setSelectedProducts4(e.value)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
</>
);
}
If you prefer a radiobutton or a checkbox instead of a row click, use the selectionMode of a column instead. Following datatable displays a checkbox at the first column of each row and automatically adds a header checkbox to toggle selection of all rows.
Tip: Use showSelectionElement function in case you need to hide selection element for a particular row.
<h5>Row and Checkbox Selection</h5>
<DataTable value={products} selection={selectedProducts} onSelectionChange={e => setSelectedProducts(e.value))}>
<Column selectionMode="multiple" />
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
<h5>Checkbox-Only Selection</h5>
<DataTable value={products} selection={selectedProducts} selectionMode="checkbox" onSelectionChange={e => setSelectedProducts(e.value))}>
<Column selectionMode="multiple" />
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="inventoryStatus" header="Status"></Column>
</DataTable>
Incell editing feature provides a way to quickly edit data inside the table. A cell editor is defined using the editor property that refers to a function to return an input element for the editing.
<DataTable value={products}>
<Column field="code" header="Code" editor={codeEditor}></Column>
<Column field="name" header="Name" editor={nameEditor}></Column>
<Column field="inventoryStatus" header="Status" body={statusBodyTemplate} editor={statusEditor}></Column>
<Column field="price" header="Price" editor={priceEditor}></Column>
</DataTable>
const onEditorValueChange = (props, value) => {
let updatedProducts = [...props.value];
updatedProducts[props.rowIndex][props.field] = value;
setProducts(updatedProducts);
}
const inputTextEditor = (props, field) => {
return <InputText type="text" value={props.rowData[field]} onChange={(e) => onEditorValueChange(props, e.target.value)} />;
}
const codeEditor = (props) => {
return inputTextEditor(props, 'code');
}
const nameEditor = (props) => {
return inputTextEditor(props, 'name');
}
const priceEditor = (props) => {
return inputTextEditor(props, 'price');
}
const statusEditor = (props) => {
return (
<Dropdown value={props.rowData['inventoryStatus']} options={statuses} optionLabel="label" optionValue="value"
onChange={(e) => onEditorValueChange(props, e.value)} style={{ width: '100%' }} placeholder="Select a Status"
itemTemplate={(option) => {
return <span className={`product-badge status-${option.value.toLowerCase()}`}>{option.label}</span>
}} />
);
}
Clicking outside the cell or hitting enter key closes the cell, however this may not be desirable if the input is invalid. In order to decide whether to keep the cell open or not, provide a cellEditValidator function that validates the value. Optionally onCellEditComplete and onCellEditCancelevents are available at the column component to provide callbacks whenever an editor is submitted or cancelled.
<DataTable value={products}>
<Column field="code" header="Code" editor={codeEditor} cellEditValidator={requiredValidator} />
<Column field="name" header="Name" editor={nameEditor} />
<Column field="price" header="Price" editor={priceDateEditor} />
</DataTable>
const requiredValidator = (e) => {
let props = e.columnProps;
let value = props.rowData[props.field];
return value && value.length > 0;
}
Row editing toggles the visibility of the all editors in the row at once and provides additional options to save and cancel editing.
<DataTable value={products} editMode="row" rowEditValidator={onRowEditValidator}>
<Column field="code" header="Code" />
<Column field="name" header="Name" />
<Column field="inventoryStatuses" header="Status" editor={statusEditor} />
<Column rowEditor />
</DataTable>
const onRowEditValidator = (rowData) => {
let value = rowData['inventoryStatuses'];
return value.length > 0;
}
DataTable provides exclusive integration with ContextMenu. contextMenuSelection and onContextMenuSelectionChange are used to get a reference of the the selected row and onContextMenu callback is utilized to display a particular context menu.
export const DataTableContextMenuDemo = () => {
const [products, setProducts] = useState([]);
const [selectedProduct, setSelectedProduct] = useState(null);
const toast = useRef(null);
const cm = useRef(null);
const menuModel = [
{label: 'View', icon: 'pi pi-fw pi-search', command: () => viewProduct(selectedProduct)},
{label: 'Delete', icon: 'pi pi-fw pi-times', command: () => deleteProduct(selectedProduct)}
];
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
const viewProduct = (product) => {
toast.current.show({severity: 'info', summary: 'Product Selected', detail: product.name});
}
const deleteProduct = (product) => {
let products = [...products];
products = products.filter((p) => p.id !== product.id);
toast.current.show({severity: 'info', summary: 'Product Deleted', detail: product.name});
setProducts(products);
}
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
const priceBodyTemplate = (rowData) => {
return formatCurrency(rowData.price);
}
return (
<div>
<Toast ref={toast}></Toast>
<ContextMenu model={menuModel} ref={cm} onHide={() => setSelectedProduct(null)}/>
<DataTable value={products} contextMenuSelection={selectedProduct}
onContextMenuSelectionChange={e => setSelectedProduct(e.value)}
onContextMenu={e => cm.current.show(e.originalEvent)}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price" body={priceBodyTemplate} />
</DataTable>
</div>
);
}
Row expansion allows displaying detailed content for a particular row. To use this feature, add an expander column, define a rowExpansionTemplate as a function to return the expanded content and bind toexpandedRows property to read the expanded rows along with the onRowToggle property to update it. expandedRows property either accepts an array of row data or a map whose key is the dataKey of the record. Using expandable rows with a dataKey is suggested for better performance.
export const DataTableRowExpansionDemo = () => {
const [products, setProducts] = useState([]);
const [expandedRows, setExpandedRows] = useState(null);
useEffect(() => {
productService = new ProductService();
productService.getProductsWithOrdersSmall().then(data => setProducts(data));
}, [])
const onRowExpand = (event) => {
toast.current.show({severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000});
}
const onRowCollapse = (event) => {
toast.current.show({severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000});
}
const expandAll = () => {
let _expandedRows = {};
products.forEach(p => expandedRows[`${p.id}`] = true);
setExpandedRows(_expandedRows);
}
const collapseAll = () => {
setExpandedRows(null);
}
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
const amountBodyTemplate = (rowData) => {
return formatCurrency(rowData.amount);
}
const statusOrderBodyTemplate = (rowData) => {
return <span className={`order-badge order-${rowData.status.toLowerCase()}`}>{rowData.status}</span>;
}
const searchBodyTemplate = () => {
return <Button icon="pi pi-search" />;
}
const imageBodyTemplate = (rowData) => {
return <img src={`images/product/${rowData.image}`} alt={rowData.image} className="product-image" />;
}
const priceBodyTemplate = (rowData) => {
return formatCurrency(rowData.price);
}
const ratingBodyTemplate = (rowData) => {
return <Rating value={rowData.rating} readonly cancel={false} />;
}
const statusBodyTemplate = (rowData) => {
return <span className={`product-badge status-${rowData.inventoryStatus.toLowerCase()}`}>{rowData.inventoryStatus}</span>;
}
const rowExpansionTemplate = (data) => {
return (
<div className="orders-subtable">
<h5>Orders for {data.name}</h5>
<DataTable value={data.orders}>
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" body={amountBodyTemplate} sortable></Column>
<Column field="status" header="Status" body={statusOrderBodyTemplate} sortable></Column>
<Column headerStyle={{ width: '4rem'}} body={searchBodyTemplate}></Column>
</DataTable>
</div>
);
}
const header = (
<div className="table-header-container">
<Button icon="pi pi-plus" label="Expand All" onClick={expandAll} className="mr-2" />
<Button icon="pi pi-minus" label="Collapse All" onClick={collapseAll} />
</div>
);
return (
<DataTable value={products} expandedRows={expandedRows} onRowToggle={(e) => setExpandedRows(e.data)}
onRowExpand={onRowExpand} onRowCollapse={onRowCollapse}
rowExpansionTemplate={rowExpansionTemplate} dataKey="id" header={header}>
<Column expander style={{ width: '3em' }} />
<Column field="name" header="Name" sortable />
<Column header="Image" body={imageBodyTemplate} />
<Column field="price" header="Price" sortable body={priceBodyTemplate} />
<Column field="category" header="Category" sortable />
<Column field="rating" header="Reviews" sortable body={ratingBodyTemplate} />
<Column field="inventoryStatus" header="Status" sortable body={statusBodyTemplate} />
</DataTable>
);
}
Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is resized. In "expand" mode, table width also changes along with the column width. onColumnResizeEnd is a callback that passes the resized column header as a parameter.
<DataTable value={products} resizableColumns>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
It is important to note that when you need to change column widths, since table width is 100%, giving fixed pixel widths does not work well as browsers scale them, instead give percentage widths.
<DataTable value={products} resizableColumns>
<Column field="code" header="Code" style={{width:'20%'}}></Column>
<Column field="name" header="Name" style={{width:'40%'}}></Column>
<Column field="category" header="Category" style={{width:'20%'}}></Column>
<Column field="quantity" header="Quantity" style={{width:'30%'}}></Column>
</DataTable>
You can choose which columns are resizeable per column.
<DataTable value={products} resizableColumns>
<Column field="code" header="Code" style={{width:'20%'}}></Column>
<Column field="name" header="Name" style={{width:'40%'}}></Column>
<Column field="category" header="Category (not resizable)" style={{width:'20%'}} resizeable={false} />
<Column field="quantity" header="Quantity" style={{width:'30%'}}></Column>
</DataTable>
Columns can be reordered using drag drop by setting the reorderableColumns to true. onColReorder is a callback that is invoked when a column is reordered. DataTable keeps the column order state internally using keys that identifies a column using the field property. If the column has no field, use columnKey instead.
<DataTable value={products} reorderableColumns>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
Data can be reordered using drag drop by adding a reorder column that will display an icon as a drag handle. onRowReorder is a callback that is invoked when a column is reordered, use this callback to update the new order. The reorder icon can be customized using rowReorderIcon of the column component.
Tip: Use showRowReorderElement function in case you need to hide selection element for a particular row.
<DataTable value={products} reorderableColumns onRowReorder={(e) => setProducts(e.value)}>
<Column rowReorder style={{width: '2em'}} />
<Column columnKey="code" field="code" header="Code"></Column>
<Column columnKey="name" field="name" header="Name"></Column>
<Column columnKey="category" field="category" header="Category"></Column>
<Column columnKey="quantity" field="quantity" header="Quantity"></Column>
</DataTable>
DataTable can export its data in CSV format using exportCSV() method.
export const DataTableExportDemo = () => {
const [products, setProducts] = useState([]);
const dt = useRef(null);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
const export = () => {
dt.exportCSV();
}
const header = <div style={{textAlign:'left'}}><Button type="button" icon="pi pi-external-link" iconPos="left" label="CSV" onClick={export}></Button></div>;
return (
<DataTable value={products} header={header} ref={dt}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
);
}
RowGrouping has two modes defined be the rowGroupMode property, in "subheader" option rows are grouped by a groupRowsBy and in "rowspan" mode grouping is done based on the sort field. In both cases, data should be sorted initally using the properties such as sortField and sortOrder. In "subheader" mode,rowGroupHeaderTemplate property should be defined to provide the content of the header and optionally rowGroupFooterTemplate is available to provide a footer for the group.
const DataTableRowGroupDemo = () => {
const [products, setProducts] = useState(null);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, []);
const headerTemplate = (data) => {
return data.name;
}
const footerTemplate = (data, index) => {
return ([
<td key={data.brand + '_footerTotalLabel'} colSpan="3" style={{textAlign: 'right'}}>Total Price</td>,
<td key={data.brand + '_footerTotalValue'}>{calculateGroupTotal(data.name)}</td>
]
);
}
const calculateGroupTotal = (name) => {
let total = 0;
if (products) {
for (let product of products) {
if (product.name === name) {
total += product.price;
}
}
}
return total;
}
return (
<div>
<DataTable header="SubHeader" value={products} rowGroupMode="subheader" sortField="brand" sortOrder={1} groupRowsBy="name"
rowGroupHeaderTemplate={headerTemplate} rowGroupFooterTemplate={footerTemplate}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price"></Column>
</DataTable>
<DataTable header="RowSpan" value={products} rowGroupMode="rowspan" sortField="brand" sortOrder={1} groupRowsBy="name"
style={{marginTop:'30px'}}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price"></Column>
</DataTable>
</div>
);
}
DataTable supports both horizontal and vertical scrolling as well as frozen columns and rows. Scrollable DataTable is enabled using scrollable property and scrollHeight to define the viewport height.
<DataTable value={products} scrollable scrollHeight="400px">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
Scrollable table uses flex layout so there are a couple of rules to consider when adjusting the widths of columns.
<Column field="code" header="Code" style={{ flex: '0 0 4rem' }}></Column>
In cases where viewport should adjust itself according to the table parent's height instead of a fixed viewport height, set scrollHeight option as flex. In example below, table is inside a Dialog where viewport size dynamically responds to the dialog size changes such as maximizing.
<Button label="Show" icon="pi pi-external-link" onClick={() => setDialogVisible(true)} />
<Dialog header="Flex Scroll" visible={dialogVisible} onHide={() => setDialogVisible(false)} style={{ width: '50vw' }} maximizable modal contentStyle={{ height: '300px' }}>
<DataTable value={products} scrollable scrollHeight="flex">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</Dialog>
FlexScroll can also be used for cases where scrollable viewport should be responsive with respect to the window size. See the
<div style={{ height: 'calc(100vh - 143px)' }}>
<DataTable value={products} scrollable scrollHeight="flex">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
For horizontal scrolling, it is required to set scrollDirection to "horizontal" and give fixed widths to columns.
<DataTable value={products} scrollable scrollDirection="horizontal">
<Column field="code" header="Code" style={{ width: '200px' }}></Column>
<Column field="name" header="Name" style={{ width: '200px' }}></Column>
<Column field="category" header="Category" style={{ width: '200px' }}></Column>
<Column field="quantity" header="Quantity" style={{ width: '200px' }}></Column>
<Column field="code" header="Code" style={{ width: '200px' }}></Column>
<Column field="name" header="Name" style={{ width: '200px' }}></Column>
<Column field="category" header="Category" style={{ width: '200px' }}></Column>
<Column field="quantity" header="Quantity" style={{ width: '200px' }}></Column>
</DataTable>
Set scrollDirection to "both" and give fixed widths to columns to scroll both ways.
<DataTable value={products} scrollable scrollDirection="both" scrollHeight="400px">
<Column field="code" header="Code" style={{ width: '200px' }}></Column>
<Column field="name" header="Name" style={{ width: '200px' }}></Column>
<Column field="category" header="Category" style={{ width: '200px' }}></Column>
<Column field="quantity" header="Quantity" style={{ width: '200px' }}></Column>
<Column field="code" header="Code" style={{ width: '200px' }}></Column>
<Column field="name" header="Name" style={{ width: '200px' }}></Column>
<Column field="category" header="Category" style={{ width: '200px' }}></Column>
<Column field="quantity" header="Quantity" style={{ width: '200px' }}></Column>
</DataTable>
Frozen rows are used to fix certain rows while scrolling, this data is defined with the frozenValue property.
<DataTable value={customers} frozenValue={lockedCustomers} scrollable scrollHeight="400px">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
</DataTable>
Certain columns can be frozen by using the frozen property of the column component. In addition alignFrozen is available to define whether the column should be fixed on the left or right.
<DataTable value={customers} scrollable scrollHeight="400px" scrollDirection="both">
<Column field="name" header="Name" style={{ width:'200px' }} frozen></Column>
<Column field="id" header="Id" style={{ width:'100px' }} frozen></Column>
<Column field="name" header="Name" style={{ width:'200px' }} </Column>
<Column field="country.name" header="Country" style={{ width:'200px' }} ></Column>
<Column field="date" header="Date" style={{ width:'200px' }} ></Column>
<Column field="company" header="Company" style={{ width:'200px' }} ></Column>
<Column field="status" header="Status" style={{ width:'200px' }} ></Column>
<Column field="activity" header="Activity" style={{ width:'200px' }} ></Column>
<Column field="representative.name" header="Representative" style={{ width:'200px' }} ></Column>
<Column field="balance" header="Balance" style={{ width:'200px' }} frozen alignFrozen="right"></Column>
</DataTable>
Row groups with subheaders have exclusive support for filtering, when the table scrolls the subheaders stay fixed as long as their data are still displayed. No additional configuration is required to enable this feature. View the
Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking corresponding callbacks everytime paging, sorting and filtering happens. Sample belows imitates lazy paging by using an in memory list. It is also important to assign the logical number of rows to totalRecords by doing a projection query for paginator configuration so that paginator displays the UI assuming there are actually records of totalRecords size although in reality they aren't as in lazy mode, only the records that are displayed on the current page exist.
In lazy mode, pagination, sorting and filtering must be used in controlled mode in addition to enabling lazy property. Here is a sample paging implementation with in memory data.
export const DataTableLazyDemo = () => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [first, setFirst] = useState(0);
const [rows, setRows] = useState(10);
const [totalRecords, setTotalRecords] = useState(0);
const [dataSource, setDataSource] = useState([]);
useEffect((() => {
productService = new ProductService();
productService.getProducts().then(data => {
setDataSource(data);
setTotalRecords(data.length);
setProducts(datasource.slice(0, rows));
setLoading(false);
});
}, []);
const onPage = (event) => {
setLoading(true);
//imitate delay of a backend call
setTimeout(() => {
const startIndex = event.first;
const endIndex = event.first + rows;
setFirst(startIndex);
setProducts(datasource.slice(startIndex, endIndex));
setLoading(false);
}, 250);
}
return (
<DataTable value={products} paginator rows={rows} totalRecords={totalRecords}
lazy first={first} onPage={onPage} loading={loading}>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
)
}
Stateful table allows keeping the state such as page, sort and filtering either at local storage or session storage so that when the page is visited again, table would render the data using its last settings. Enabling state is easy as defining a unique stateKey, the storage to keep the state is defined with the stateStorage property that accepts session for sessionStorage and local for localStorage. Also, a special storage implementation can be made with customSaveState and customRestoreState methods using stateStorage="custom". Currently following features are supported by TableState; paging, sorting, filtering, column resizing, column reordering, row expansion and row selection.
export const DataTableStateDemo = () => {
const [products, setProducts] = useState([]);
const [selectedProducts, setSelectedProducts] = useState(null);
useEffect(() => {
productService = new ProductService();
productService.getProductsSmall().then(data => setProducts(data));
}, [])
return (
<DataTable value={products} selectionMode="multiple" resizableColumns
selection={selectedProducts} onSelectionChange={e => setSelectedProducts(e.value)}
paginator rows={10} stateKey="tablestatedemo-session">
<Column field="code" header="Code" sortable filter></Column>
<Column field="name" header="Name" sortable filter></Column>
<Column field="category" header="Category" sortable filter></Column>
<Column field="quantity" header="Quantity" sortable filter></Column>
</DataTable>
);
}
DataTable responsive layout can be achieved in two ways; first approach is displaying a horizontal scrollbar for smaller screens and second one is defining a breakpoint to display the cells of a row as stacked. Scrollable tables use the scroll layout approach internally and do not require additional configuration.
Set responsiveLayout to scroll to enabled this layout. Note that, when scroll mode is enabled table-layout automatically switches to auto from fixed as a result table widths are likely to differ and resizable columns are not supported. Read more about table-layout for more details.
<DataTable value={products} responsiveLayout="scroll">
</DataTable>
In stack layout, columns are displayed as stacked after a certain breakpoint. Default is '960px'.
<DataTable value={products} responsiveLayout="stack" breakpoint="640px">
</DataTable>
Any valid attribute is passed to the root element implicitly, extended properties are as follows;
Name | Type | Default | Description |
---|---|---|---|
id | string | null | Unique identifier of the element. |
value | array | null | An array of objects to display. |
header | any | null | Header content of the table. |
footer | any | null | Footer content of the table. |
style | object | null | Inline style of the component. |
className | any | null | Style class of the component. |
tableStyle | object | null | Inline style of the table element. |
tableClassName | string | null | Style class of the table element. |
paginator | boolean | false | When specified as true, enables the pagination. |
paginatorPosition | string | bottom | Position of the paginator, options are "top","bottom" or "both". |
alwaysShowPaginator | boolean | true | Whether to show it even there is only one page. |
paginatorClassName | string | null | Style class of the paginator element. |
paginatorTemplate | string|object | FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown | Template of the paginator. For details, refer to the template section of the paginator documentation for further options. |
paginatorLeft | Element | null | Content for the left side of the paginator. |
paginatorRight | Element | null | Content for the right side of the paginator. |
pageLinkSize | number | 5 | Number of page links to display. |
rowsPerPageOptions | array | null | Array of integer values to display inside rows per page dropdown. |
currentPageReportTemplate | string | ({currentPage} of {totalPages}) | Template of the current page report element. Available placeholders are {currentPage}, {totalPages}, {rows}, {first}, {last} and {totalRecords} |
paginatorDropdownAppendTo | DOM element | string | document.body | DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. |
first | number | 0 | Index of the first row to be displayed. |
rows | number | null | Number of rows to display per page. |
totalRecords | number | null | Number of total records, defaults to length of value when not defined. |
lazy | boolean | false | Defines if data is loaded and interacted with in lazy manner. |
sortField | string | null | Name of the field to sort data by default. |
sortOrder | number | null | Order to sort the data by default. |
multiSortMeta | array | null | An array of SortMeta objects to sort the data by default in multiple sort mode. |
sortMode | string | single | Defines whether sorting works on single column or on multiple columns. |
defaultSortOrder | number | 1 | Default sort order of an unsorted column. |
removableSort | boolean | false | When enabled, columns can have an un-sorted state. |
emptyMessage | any | No records found | Text to display when there is no data. |
selectionMode | string | null | Specifies the selection mode, valid values are "single", "multiple", "radiobutton" and "checkbox". |
dragSelection | boolean | false | When enabled, a rectangle that can be dragged can be used to make a range selection. |
selection | any | null | Selected row in single mode or an array of values in multiple mode. |
selectionAriaLabel | string | null | A field property from the row to add "Select {field}" and "Unselect {field}" ARIA labels to checkbox/radio buttons. |
contextMenuSelection | any | null | Selected row in single mode or an array of values in multiple mode. |
compareSelectionBy | string | deepEquals | Algorithm to define if a row is selected, valid values are "equals" that compares by reference and "deepEquals" that compares all fields. |
dataKey | string | null | A property to uniquely identify a record in data. |
metaKeySelection | boolean | true | Defines whether metaKey is requred or not for the selection. When true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. |
selectionPageOnly | boolean | false | When enabled with paginator and checkbox selection mode, the select all checkbox in the header will select all rows on the current page. |
selectionAutoFocus | boolean | true | When a selectable row is clicked on RadioButton and Checkbox selection, it automatically decides whether to focus on elements such as checkbox or radio. |
selectOnEdit | boolean | true | Determines whether the cell editor will be opened when clicking to select any row on Selection and Cell Edit modes. |
headerColumnGroup | ColumnGroup | null | ColumnGroup component for header. |
footerColumnGroup | ColumnGroup | null | ColumnGroup component for footer. |
rowExpansionTemplate | function | null | Function that receives the row data as the parameter and returns the expanded row content. You can override the rendering of the content by setting options.customRendering = true. |
expandedRows | array|object | null | A collection of rows or a map object row data keys that are expanded. |
resizableColumns | boolean | false | When enabled, columns can be resized using drag and drop. |
columnResizeMode | string | fit | Defines whether the overall table width should change on column resize, valid values are "fit" and "expand". |
reorderableColumns | boolean | false | When enabled, columns can be reordered using drag and drop. |
reorderableRows | boolean | false | When enabled, rows can be reordered using drag and drop. |
filters | array | null | An array of FilterMetadata objects to provide external filters. |
filterDelay | number | 300 | Delay in milliseconds before filtering the data. |
filterLocale | string | undefined | Locale to use in filtering. The default locale is the host environment's current locale. |
scrollable | boolean | false | When specified, enables horizontal and/or vertical scrolling. |
scrollHeight | string | null | Height of the scroll viewport. |
scrollDirection | string | vertical|horizontal | Orientation of the scrolling, options are "vertical", "horizontal" and "both". |
virtualScrollerOptions | object | null | Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. Note: Currently only vertical orientation mode is supported. |
frozenWidth | string | null | Width of the frozen part in scrollable DataTable. |
frozenValue | array | null | Items of the frozen part in scrollable DataTable. |
csvSeparator | string | , | Character to use as the csv separator. |
exportFilename | string | download | Name of the exported file. |
rowGroupMode | string | null | Defines the row grouping mode, valid values are "subheader" and "rowgroup". |
autoLayout | boolean | false | Whether the cell widths scale according to their content or not. |
rowClassName | function | null | Function that takes the row data and returns an object in "{'styleclass' : condition}" format to define a classname for a particular now. |
cellClassName | function | null | Function that takes the cell data and returns an object in "{'styleclass' : condition}" format to define a classname for a particular now. |
rowGroupHeaderTemplate | function | null | Function to provide the content of row group header. |
rowGroupFooterTemplate | function | null | Function to provide the content of row group footer. |
loading | boolean | false | Displays a loader to indicate data load is in progress. |
loadingIcon | string | pi pi-spinner | The icon to show while indicating data load is in progress. |
tabIndex | number | null | Index of the element in tabbing order. |
stateKey | string | null | Unique identifier of a stateful table to use in state storage. |
stateStorage | string | session | Defines where a stateful table keeps its state, valid values are "session" for sessionStorage, "local" for localStorage and "custom". |
editMode | string | cell | Defines editing mode, options are "cell" and "row". |
editingRows | array|object | null | A collection of rows to represent the current editing data in row edit mode. |
exportFunction | function | null | A function to implement custom export. Need to return string value. event.data: Field data. event.field: Column field. event.rowData: Row data. event.column: Column. |
expandableRowGroups | boolean | false | Makes row groups toggleable, default is false. |
rowHover | boolean | false | When enabled, background of the rows change on hover. |
showGridlines | boolean | false | Whether to show grid lines between cells. |
stripedRows | boolean | false | Whether to displays rows with alternating colors. |
size | string | normal | Define to set alternative sizes. Valid values: "small", "normal" and "large". |
responsiveLayout | string | stack | Defines the responsive mode, valid options are "stack" and "scroll". |
breakpoint | string | 960px | The breakpoint to define the maximum width boundary when using stack responsive layout. |
filterDisplay | string | menu | Layout of the filter elements, valid values are "row" and "menu". |
expandedRowIcon | string | pi pi-chevron-down | Icon of the row toggler to display the row as expanded. |
collapsedRowIcon | string | pi pi-chevron-up | Icon of the row toggler to display the row as collapsed. |
globalFilter | any | null | Value of the global filter to use in filtering. |
globalFilterFields | string[] | null | Define fields to be filtered globally. |
globalFilterMatchMode | string | contains | Defines filterMatchMode; "startsWith", "contains", "endsWith", "equals", "notEquals", "in", "lt", "lte", "gt", "gte" and "custom". |
showSelectionElement | function | null | Function that returns a boolean by passing the row data to decide if the radio or checkbox should be displayed per row. |
showRowReorderElement | function | null | Function that returns a boolean by passing the row data to decide if the row reorder element should be displayed per row. |
isDataSelectable | function | null | Function that returns a boolean to decide whether the data should be selectable. |
customSaveState | function | null | A function to implement custom saveState with stateStorage="custom". state: the object to be stored. |
customRestoreState | function | null | A function to implement custom restoreState with stateStorage="custom". Need to return state object. |
Name | Parameters | Description |
---|---|---|
onSelectionChange | event.originalEvent: Browser event event.value: Selection object | Callback to invoke when selection changes. |
onContextMenuSelectionChange | event.originalEvent: Browser event event.value: Selection object | Callback to invoke when a row selected with right click. |
onRowToggle | event.data: Expanded rows | Callback to invoke when a row is toggled or collapsed. |
onColumnResizeEnd | event.element: DOM element of the resized column. event.column: Properties of the resized column. event.delta: Change in column width | Callback to invoke when a column is resized. |
onColumnResizerClick | event.originalEvent: Browser event event.element: DOM element of the column. event.column: Properties of the column. | Callback to invoke when a resizer element is clicked. |
onColumnResizerDoubleClick | event.originalEvent: Browser event event.element: DOM element of the column. event.column: Properties of the column. | Callback to invoke when a resizer element is double clicked. |
onSort | event.sortField: Field to sort against. event.sortOrder: Sort order as integer. event.multiSortMeta: MultiSort metadata. | Callback to invoke on sort. |
onPage | event.first: Index of the first row. event.rows: Rows per page. | Callback to invoke on pagination. |
onFilter | event.filters: Collection of active filters. | Callback to invoke on filtering. |
onAllRowsSelect | event.originalEvent: Browser event. event.data: Selected rows data. event.type: Type of the selection, valid value is "all". | Callback to invoke when all rows are selected using the header checkbox. |
onAllRowsUnselect | event.originalEvent: Browser event. event.data: Unselected rows data. event.type: Type of the selection, valid value is "all". | Callback to invoke when all rows are unselected using the header checkbox. |
onRowClick | event.originalEvent: Browser event event.data: Clicked row data event.index: Clicked row data index | Callback to invoke when a row is clicked. |
onRowDoubleClick | event.originalEvent: Browser event event.data: Clicked row data event.index: Clicked row data index | Callback to invoke when a row is double clicked. |
onRowSelect | event.originalEvent: Browser event. event.data: Selected row data. event.type: Type of the selection, valid values are "row", "radio" or "checkbox". | Callback to invoke when a row is selected. |
onRowUnselect | event.originalEvent: Browser event. event.data: Unselected row data. event.type: Type of the selection, valid values are "row", "radio" or "checkbox". | Callback to invoke when a row is unselected. |
onRowExpand | event.originalEvent: Browser event. event.data: Expanded row data. | Callback to invoke when a row is expanded. |
onRowCollapse | event.originalEvent: Browser event. event.data: Collapsed row data. | Callback to invoke when a row is collapsed. |
onContextMenu | event.originalEvent: Original event instance. event.data: Collapsed row data | Callback to invoke when a context menu is clicked. |
onColReorder | event.originalEvent: Browser event event.dragIndex: Index of the dragged column event.dropIndex: Index of the dropped column event.columns: Columns array after reorder. | Callback to invoke when a column is reordered. |
onRowOrder | event.originalEvent: Browser event. event.value: New value after reorder event.dragIndex: Index of the dragged row event.dropIndex: Index of the drop location | Callback to invoke when a row is reordered. |
onValueChange | value: Value displayed by the table. | Callback to invoke after filtering and sorting to pass the rendered value. |
rowEditValidator | data: Editing row data | Callback to invoke to validate the editing row when the save icon is clicked on row editing mode. |
onRowEditInit | event.originalEvent: Browser event event.data: Editing row data | Callback to invoke when the editing icon is clicked on row editing mode. |
onRowEditSave | event.originalEvent: Browser event event.data: Editing row data | Callback to invoke when the save icon is clicked on row editing mode. |
onRowEditCancel | event.originalEvent: Browser event event.data: Editing row data event.index: Editing row data index | Callback to invoke when the cancel icon is clicked on row editing mode. |
onRowEditChange | event.originalEvent: Browser event event.data: Editing rows data event.index: Current editing row data index | Callback to invoke when the row editor is programmatically shown/hidden on row editing mode. |
onRowEditComplete | event.originalEvent: Browser event event.data: Original rows data event.newData: Editing rows data event.field: Column field event.index: Current editing row data index | Callback to invoke when row edit is completed. |
onStateSave | state: Table state | Callback to invoke table state is saved. |
onStateRestore | state: Table state | Callback to invoke table state is restored. |
Name | Parameters | Description |
---|---|---|
reset | - | Resets sort, filter, paginator and columnorder state. |
exportCSV | - | Exports the data to CSV format. |
filter | value: the filter value field: the filter field mode: filter match mode. | Filters the data. |
closeEditingCell | - | Closes the current editing cell when incell editing is enabled. |
resetColumnOrder | - | Resets column order when reorderableColumns is enabled. |
resetScroll | - | Resets scroll position. |
restoreTableState | state | Stored states can be loaded at any time using this method if there is a stateStorage property. |
Following is the list of structural style classes, for theming classes visit theming page.
Name | Element |
---|---|
p-datatable | Container element. |
p-datatable-scrollable | Container element when table is scrollable. |
p-datatable-header | Header section. |
p-datatable-footer | Footer section. |
p-datatable-wrapper | Wrapper of table element. |
p-datatable-table | Table element. |
p-datatable-thead | Table thead element. |
p-datatable-tbody | Table tbody element. |
p-datatable-tfoot | Table tfoot element. |
p-column-title | Title of a column. |
p-sortable-column | Sortable column header. |
p-frozen-column | Frozen column header. |
p-rowgroup-header | Header of a rowgroup. |
p-rowgroup-footer | Footer of a rowgroup. |
p-datatable-row-expansion | Expanded row content. |
p-row-toggler | Toggle element for row expansion. |
p-datatable-emptymessage | Cell containing the empty message. |
p-row-editor-init | Pencil button of row editor. |
p-row-editor-init | Save button of row editor. |
p-row-editor-init | Cancel button of row editor. |
This section is under development. After the necessary tests and improvements are made, it will be shared with the users as soon as possible.
None.
Built-in component themes created by the PrimeReact Theme Designer.
Premium themes are only available exclusively for PrimeReact Theme Designer subscribers and therefore not included in PrimeReact core.
Beautifully crafted premium create-react-app application templates by the PrimeTek design team.