Table
Table of Contents
Caption#
A caption that describes the content of the table can be set in two ways. It's mandatory to define a descriptive caption
to fulfill accessibility criteria.
Via property
Using the caption property doesn't display the caption but instead can be used to improve accessibility of the table.
Via slot
When using the caption slot its content will be rendered while offering full control of appearance.
Layout: fixed#
By setting layout to fixed you can get full control over every column width that are otherwise controlled by their
content. An identical width, min-width and/or max-width depending on what you want to achieve, has to be specified
on every p-table-head-cell and p-table-cell within the same column .
While it is possible to use relative width units likes 50% or 50vw, these may lead to unexpected results when the
table is scrollable especially on smaller screens or when combined with absolute (e.g. 50px) or default auto values
(based on content).
If there is more content than available space, it will be overflowing, which you need to take care of, e.g. by using
<p-text ellipsis>Some content</p-text>.
Since truncated content cannot be fully read, it is important to provide an alternative like a title
attribute or custom tooltip.
Column Headers#
The p-table's head can be configured by setting one or more of the following properties on each p-table-head-cell.
Sorting
In order to have a sortable table column you need to provide the sort property. It has the following structure:
type TableHeadCellSort = {
id : string ;
active: boolean ;
direction: 'asc' | 'desc' ;
};
Upon clicking a sortable p-table-head-cell element, the p-table emits an update event that you should subscribe
to.
The sortingChange event has been deprecated and will be removed with the next major release.
Please use the update event instead.
prev nextVanilla JS Angular React Vue Open in Stackblitz<!doctype html>
< html lang = "en" class = "auto" >
< head >
< title > </ title >
</ head >
< body class = "bg-canvas" >
< p-table caption = "Some caption" > </ p-table >
< script >
( () => {
const headSorting = [
{ name : 'Column 1' , id : 'col1' },
{ name : 'Column 2' , id : 'col2' },
{ name : 'Column 3' , id : 'col3' },
];
const dataSorting = [
{
col1 : 'Name A' ,
col2 : '9' ,
col3 : '01.06.2021' ,
},
{
col1 : 'Name Z' ,
col2 : '1' ,
col3 : '24.06.2021' ,
},
];
const renderTableHeadRow = ( items ) =>
[
'<p-table-head-row>' ,
...items.map( ( item ) => `<p-table-head-cell> ${item.name} </p-table-head-cell>` ),
'</p-table-head-row>' ,
].join( '' );
const renderTableBodyRows = ( items ) =>
items
.map(
( item ) => `
<p-table-row>
<p-table-cell> ${item.col1} </p-table-cell>
<p-table-cell> ${item.col2} </p-table-cell>
<p-table-cell> ${item.col3} </p-table-cell>
</p-table-row>`
)
.join( '' );
const markup = `
<p-table-head> ${renderTableHeadRow(headSorting)} </p-table-head>
<p-table-body> ${renderTableBodyRows(dataSorting)} </p-table-body>` ;
const table = document .querySelector( 'p-table' );
table.innerHTML = markup;
const tableHeadCells = table.querySelectorAll( 'p-table-head-cell' );
const tableBody = table.querySelector( 'p-table-body' );
tableHeadCells.forEach( ( cell, index ) => {
cell.sort = { id : index.toString(), active : false , direction : 'asc' };
});
table.addEventListener( 'update' , ( e ) => {
const { id, direction } = e.detail;
tableHeadCells.forEach( ( cell, index ) => {
cell.sort = {
id : index.toString(),
active : index === Number (id),
direction : index === Number (id) ? direction : 'asc' ,
};
});
const rows = Array .from(tableBody.querySelectorAll( 'p-table-row' ));
const sortedRows = rows.sort( ( a, b ) => {
const aText = a.querySelectorAll( 'p-table-cell' )[id].textContent.trim();
const bText = b.querySelectorAll( 'p-table-cell' )[id].textContent.trim();
const compare = aText.localeCompare(bText);
return direction === 'asc' ? compare : -compare;
});
sortedRows.forEach( row => tableBody.appendChild(row));
});
})();
</ script >
</ body >
</ html >
Hide Label
Sometimes you want to hide the label of a table column for example when the column's content is self-explanatory. This
can be achieved by setting the hide-label property.
Advanced Table#
The appearance of a table's contents can be customized as illustrated in the following example.
prev nextVanilla JS Angular React Vue Open in Stackblitz<!doctype html>
< html lang = "en" class = "auto" >
< head >
< title > </ title >
</ head >
< body class = "bg-canvas" >
< p-table >
< p-heading slot = "caption" variant = "large" tag = "h3" > Some visual caption </ p-heading >
< p-table-head > </ p-table-head >
< p-table-body > </ p-table-body >
</ p-table >
< script >
(() => {
const headAdvanced = [
{ name: 'Model', id: 'model' },
{ name: 'Interest', id: 'interest' },
{ name: 'VIN', id: 'vin' },
{ name: 'Purchase Intention', id: 'purchaseIntention' },
{ name: 'Status', id: 'status' },
{ name: 'Comment', id: 'comment' },
{ name: 'Lead ID', id: 'leadId' },
{ name: 'Select Wrapper', id: 'selectWrapper' },
{ name: 'Select', id: 'select' },
{ name: 'Multi-Select', id: 'multiSelect' },
{ name: 'Action', id: 'action', hideLabel: true },
].map((item, i) => ({
...item,
...(i > 0 &&
i < 7 &&
i !== 5 && {
active: i === 1,
direction: 'asc',
}),
}));
const dataAdvanced = [
{
imageUrl: 'assets/718.png',
model: '718',
date: '23.06.2021',
interest: 'New Car',
vin: '1FM5K7F84FGB16304',
purchaseIntention: '08/2021',
status: 'Won',
comment: '-',
leadId: '0000824402',
},
{
imageUrl: 'assets/panamera.png',
model: 'Panamera',
date: '19.06.2021',
interest: 'New Car',
vin: '2GCEC13T141374801',
purchaseIntention: '11/2021',
status: 'Lost',
comment: 'Some multiline text and a column with a min width.',
leadId: '0000824409',
},
{
imageUrl: 'assets/911.png',
model: '911',
date: '19.05.2021',
interest: 'Used Car',
vin: '5GAKVCKD8EJ335750',
purchaseIntention: '09/2021',
status: 'Won',
comment: '-',
leadId: '0000824408',
},
{
imageUrl: 'assets/macan.png',
model: 'Macan',
date: '10.05.2021',
interest: 'Used Car',
vin: '1FMPU17L83LC09302',
purchaseIntention: '07/2021',
status: 'Lost',
comment: '-',
leadId: '0000824407',
},
{
imageUrl: 'assets/taycan.png',
model: 'Taycan',
date: '03.05.2021',
interest: 'New Car',
vin: 'JN1BY1AR3BM375187',
purchaseIntention: '05/2021',
status: 'Won',
comment: '-',
leadId: '0000824406',
},
];
const renderTableHeadRow = (items) =>
[
' < p-table-head-row > ',
...items.map((item) => ` < p-table-head-cell > ${item.name || ''} </ p-table-head-cell > `),
' </ p-table-head-row > ',
].join('');
const renderTableBodyRows = (items) =>
items
.map(
(item) => `
< p-table-row >
< p-table-cell >
< div style = "display: flex;" >
< img src = "${item.imageUrl}" width = "80" height = "45" style = "margin-right: .5rem; object-fit: contain; max-width: none;" alt = "" />
< div >
< p-text weight = 'semi-bold' > ${item.model} </ p-text >
< p-text size = 'x-small' > ${item.date} </ p-text >
</ div >
</ div >
</ p-table-cell >
< p-table-cell > ${item.interest} </ p-table-cell >
< p-table-cell > < a href = "https://porsche.com" > ${item.vin} </ a > </ p-table-cell >
< p-table-cell > ${item.purchaseIntention} </ p-table-cell >
< p-table-cell > ${item.status} </ p-table-cell >
< p-table-cell multiline = "true" style = "min-width: 10rem;" > ${item.comment} </ p-table-cell >
< p-table-cell > ${item.leadId} < p-popover description = "Some additional content." > </ p-popover > </ p-table-cell >
< p-table-cell >
< p-select-wrapper label = "Select Something" style = "min-width: 160px;" >
< select name = "some-name" >
< option value = "a" > Option A </ option >
< option value = "b" > Option B </ option >
< option value = "c" > Option C </ option >
< option value = "d" > Option D </ option >
< option value = "e" > Option E </ option >
< option value = "f" > Option F </ option >
< option value = "g" > Option G </ option >
< option value = "h" > Option H </ option >
< option value = "i" > Option I </ option >
< option value = "j" > Option J </ option >
< option value = "k" > Option K </ option >
</ select >
</ p-select-wrapper >
</ p-table-cell >
< p-table-cell >
< p-select name = "options" label = "Select Something" style = "min-width: 160px; display: block;" >
< p-select-option value = "a" > Option A </ p-select-option >
< p-select-option value = "b" > Option B </ p-select-option >
< p-select-option value = "c" > Option C </ p-select-option >
< p-select-option value = "d" > Option D </ p-select-option >
< p-select-option value = "e" > Option E </ p-select-option >
< p-select-option value = "f" > Option F </ p-select-option >
< p-select-option value = "g" > Option G </ p-select-option >
< p-select-option value = "h" > Option H </ p-select-option >
< p-select-option value = "i" > Option I </ p-select-option >
< p-select-option value = "j" > Option J </ p-select-option >
< p-select-option value = "k" > Option K </ p-select-option >
</ p-select >
</ p-table-cell >
< p-table-cell >
< p-multi-select name = "name" label = "Multi-Select Something" style = "min-width: 160px;" >
< p-multi-select-option value = "a" > Option A </ p-multi-select-option >
< p-multi-select-option value = "b" > Option B </ p-multi-select-option >
< p-multi-select-option value = "c" > Option C </ p-multi-select-option >
< p-multi-select-option value = "d" > Option D </ p-multi-select-option >
< p-multi-select-option value = "e" > Option E </ p-multi-select-option >
< p-multi-select-option value = "f" > Option F </ p-multi-select-option >
< p-multi-select-option value = "g" > Option G </ p-multi-select-option >
< p-multi-select-option value = "h" > Option H </ p-multi-select-option >
< p-multi-select-option value = "i" > Option I </ p-multi-select-option >
< p-multi-select-option value = "j" > Option J </ p-multi-select-option >
< p-multi-select-option value = "k" > Option K </ p-multi-select-option >
</ p-multi-select >
</ p-table-cell >
< p-table-cell >
< p-button-pure icon = "edit" style = "padding: .5rem" > Edit </ p-button-pure >
< p-button-pure icon = "delete" style = "padding: .5rem" > Delete </ p-button-pure >
</ p-table-cell >
</ p-table-row > `
)
.join('');
const table = document.querySelector('p-table');
const tableHead = table.querySelector('p-table-head');
tableHead.innerHTML = renderTableHeadRow(headAdvanced);
const tableBody = table.querySelector('p-table-body');
tableBody.innerHTML = renderTableBodyRows(dataAdvanced);
const tableHeadCells = table.querySelectorAll('p-table-head-cell');
tableHeadCells.forEach((cell, index) => {
cell.sort = { id: index.toString(), active: false, direction: 'asc' };
});
table.addEventListener('update', (e) => {
const { id, direction } = e.detail;
tableHeadCells.forEach((cell, index) => {
cell.sort = {
id: index.toString(),
active: index === Number(id),
direction: index === Number(id) ? direction : 'asc',
};
});
const rows = Array.from(tableBody.querySelectorAll('p-table-row'));
const sortedRows = rows.sort((a, b) => {
const aText = a.querySelectorAll('p-table-cell')[id].textContent.trim();
const bText = b.querySelectorAll('p-table-cell')[id].textContent.trim();
const compare = aText.localeCompare(bText);
return direction === 'asc' ? compare : -compare;
});
sortedRows.forEach(row => tableBody.appendChild(row));
});
})();
</ script >
</ body >
</ html >