Table
<ol-table> | OlTable
Table component.
<ol-table id="default-example" style="height: 280px;"></ol-table> <script> // Data generation self.allData = new Array(1000).fill(0).map((_, index) => { return { id: index + 1, title: `Post #${index + 1}`, status: ['published', 'pending', 'draft'][Math.floor(Math.random() * 3)], visits: Math.ceil(Math.random() * 1000), createdAt: new Date(Date.now() + index * 47 * 60 * 60 * 1000) }; }); const table = document.querySelector('#default-example'); table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.data = self.allData.slice(0, 10); </script>
import OlTable from '@onlive.site/ui/dist/react/table'; const App = () => ( <> <OlTable columns={[ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]} data={self.allData.slice(0, 10)} > </OlTable> </> );
Examples
Column and Cell formatting
Customize the headers and cells.
<ol-table id="custom-header-cell-example" style="height: 280px;"></ol-table> <script> const table = document.querySelector('#custom-header-cell-example'); table.columns = [ { header: "ID", accessorKey: 'id', size: 50, }, { header: "Title", // or header: () => html`<span>Title</span>` accessorKey: 'title', size: 50, }, { header: "Visits", accessorKey: 'visits', size: 50, }, { header: 'Status', accessorKey: 'status', size: 50, cell: info => { const value = info.getValue(); const badge = document.createElement('ol-badge'); badge.pill = true; badge.textContent = value; switch(value) { case 'published': badge.variant = 'success'; break; case 'pending': badge.variant = 'warning'; break; case 'draft': badge.variant = 'neutral'; break; } return badge; } }, { header: 'Created At', accessorFn: row => row.createdAt.toLocaleString(), } ]; table.data = self.allData.slice(0, 10); </script>
Actions Column
Add an actions column with buttons for row-specific actions.
<ol-table id="actions-column-example" style="height: 280px;"></ol-table> <script> const table = document.querySelector('#actions-column-example'); table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'status', size: 50 }, { header: 'Actions', id: 'actions', size: 120, enableSorting: false, cell: info => { const row = info.row.original; const container = document.createElement('div'); container.style.display = 'flex'; container.style.gap = '8px'; // Edit button const editBtn = document.createElement('ol-button'); editBtn.size = 'small'; editBtn.variant = 'default'; editBtn.textContent = 'Edit'; editBtn.addEventListener('click', () => { alert(`Edit row ${row.id}`); }); // Delete button const deleteBtn = document.createElement('ol-button'); deleteBtn.size = 'small'; deleteBtn.variant = 'danger'; deleteBtn.textContent = 'Delete'; deleteBtn.addEventListener('click', () => { if (confirm(`Delete ${row.title}?`)) { alert(`Deleted row ${row.id}`); } }); container.appendChild(editBtn); container.appendChild(deleteBtn); return container; } } ]; table.data = self.allData.slice(0, 10); </script>
Selection
Use the selectionMode
property to set the selection mode to single or multiple.
Multiple selection
<ol-table id="multiple-selection-example" style="height: 280px;"></ol-table> <p id="selected-rows-multiple"></p> <script> const table = document.querySelector('#multiple-selection-example'); table.selectionMode = "multiple"; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.data = self.allData.slice(0, 10); table.addEventListener('ol-row-select', ({ detail }) => { document.querySelector("#selected-rows-multiple").textContent = `Selected rows: ${Object.keys(detail).join(', ')}` }); </script>
Single selection
<ol-table id="single-selection-example" style="height: 280px;"></ol-table> <p id="selected-rows-single"></p> <script> const table = document.querySelector('#single-selection-example'); table.selectionMode = "single"; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.data = self.allData.slice(0, 10); table.addEventListener('ol-row-select', ({ detail }) => { document.querySelector("#selected-rows-single").textContent = `Selected rows: ${Object.keys(detail).join(', ')}` }); </script>
Pagination
Client-side Pagination
<ol-table id="pagination-client-example" style="height: 280px;"></ol-table> <script> const table = document.querySelector('#pagination-client-example'); table.paginationMode = "client"; // By default is `client` table.pagination = { pageIndex: 0, pageSize: 10 }; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.data = self.allData; </script>
Server-side Pagination
Use the paginationMode
property to set the server-side pagination.
<ol-table id="pagination-server-example" style="height: 280px;"></ol-table> <script> const fetchData = async (page, size) => { return new Promise((resolve) => setTimeout(() => resolve(self.allData.slice(page * size, (page + 1) * size)), 750)); } const table = document.querySelector('#pagination-server-example'); const pageSize = 10; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.paginationMode = 'server'; table.pagination = { pageIndex: 0, pageSize, pageCount: Math.floor(self.allData.length / pageSize), }; table.data = self.allData.slice(0, pageSize); table.addEventListener('ol-paginate', async ({ detail: { pageIndex, pageSize } }) => { table.loading = true; table.pagination = { pageIndex, pageSize, pageCount: Math.floor(self.allData.length / pageSize), }; table.data = await fetchData(pageIndex, pageSize) table.loading = false; }); </script>
Infinite-scroll Pagination
Use the paginationType
property to set the infinite scroll pagination.
<ol-table id="infinite-scroll-example" style="height: 280px;"></ol-table> <script> const fetchData = async (page, size) => { return new Promise((resolve) => setTimeout(() => resolve(self.allData.slice(page * size, (page + 1) * size)), 750)); } const table = document.querySelector('#infinite-scroll-example'); const pageSize = 10; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.paginationMode = 'server'; table.paginationType = 'infinite-scroll'; table.pagination = { pageIndex: 0, pageSize, pageCount: Math.floor(self.allData.length / pageSize), }; table.selectionMode = "multiple"; table.data = self.allData.slice(0, pageSize); table.addEventListener('ol-paginate', async ({ detail: { pageIndex, pageSize } }) => { table.loading = true; table.pagination = { pageIndex, pageSize, pageCount: Math.floor(self.allData.length / pageSize), }; table.data = [...table.data, ...(await fetchData(pageIndex, pageSize))]; table.loading = false; }); </script>
Sorting
Use the sortingMode
property to set the sorting mode to client or server. Defaults is server.
Client-side Sorting
<ol-table id="sorting-client-example" style="height: 280px;"></ol-table> <script> // Custom sort function const sortStatusFn = (rowA, rowB) => { const statusA = rowA.original.status; const statusB = rowB.original.status; const statusOrder = ['published', 'pending', 'draft']; return statusOrder.indexOf(statusA) - statusOrder.indexOf(statusB); }; const table = document.querySelector('#sorting-client-example'); table.sortingMode = "client"; table.sorting = [{ id: 'visits', desc: true }]; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50, sortingFn: sortStatusFn }, { accessorKey: 'createdAt' } ]; table.data = self.allData.slice(0, 10); </script>
Server-side Sorting
<ol-table id="sorting-server-example" style="height: 280px;"></ol-table> <script> const fetchData = async (page, size, sortFields = []) => { return new Promise((resolve) => setTimeout(() => { if (sortFields[0]) { self.allData.sort((a, b) => { return (a[sortFields[0].id] > b[sortFields[0].id] ? 1 : -1) * (sortFields[0].desc ? -1 : 1); }); } resolve(self.allData.slice(page * size, (page + 1) * size)); }, 750) ); } const table = document.querySelector('#sorting-server-example'); table.sortingMode = "server"; table.columns = [ { accessorKey: 'id', size: 50 }, { accessorKey: 'title', size: 50 }, { accessorKey: 'visits', size: 50 }, { accessorKey: 'status', size: 50 }, { accessorKey: 'createdAt' } ]; table.data = self.allData.slice(0, 10); table.addEventListener('ol-column-sort', async ({ detail }) => { table.loading = true; table.data = await fetchData(0, 10, detail) table.loading = false; }); </script>
All features
<ol-table id="all-features-example" style="height: 350px;"></ol-table> <p id="selected-rows-all-features"></p> <script> const fetchData = async (page, size, sortFields = []) => { return new Promise((resolve) => setTimeout(() => { if (sortFields[0]) { self.allData.sort((a, b) => { return (a[sortFields[0].id] > b[sortFields[0].id] ? 1 : -1) * (sortFields[0].desc ? -1 : 1); }); } resolve(self.allData.slice(page * size, (page + 1) * size)); }, 750) ); } const pageSize = 10; const table = document.querySelector('#all-features-example'); table.selectionMode = "multiple"; table.sortingMode = "server"; table.paginationMode = 'server'; table.pagination = { pageIndex: 0, pageSize, pageCount: Math.floor(self.allData.length / pageSize), }; table.columns = [ { header: "ID", accessorKey: 'id', size: 50, }, { header: "Title", // or header: () => html`<span>Title</span>` accessorKey: 'title', size: 50, }, { header: "Visits", accessorKey: 'visits', size: 50, }, { header: 'Status', accessorKey: 'status', size: 50, cell: info => { const value = info.getValue(); const badge = document.createElement('ol-badge'); badge.pill = true; badge.textContent = value; switch(value) { case 'published': badge.variant = 'success'; break; case 'pending': badge.variant = 'warning'; break; case 'draft': badge.variant = 'neutral'; break; } return badge; } }, { header: 'Created At', accessorFn: row => row.createdAt.toLocaleString(), } ]; table.data = self.allData.slice(0, pageSize); table.addEventListener('ol-paginate', async ({ detail: { pageIndex, pageSize } }) => { table.loading = true; table.pagination = { pageIndex, pageSize, pageCount: Math.floor(self.allData.length / pageSize), }; table.data = await fetchData(pageIndex, pageSize) table.loading = false; }); table.addEventListener('ol-row-select', ({ detail: rowSelection }) => { document.querySelector("#selected-rows-all-features").textContent = `Selected rows: ${Object.keys(rowSelection).join(', ')}` }); table.addEventListener('ol-column-sort', async ({ detail: sortFields }) => { table.loading = true; table.data = await fetchData(0, pageSize, sortFields) table.loading = false; }); </script>
import OlTable from '@onlive.site/ui/dist/react/table'; import { createRoot } from "react-dom/client"; import { useState } from "react"; import { SortingState } from "@onlive.site/ui/dist/components/table/table.component.js"; const STATUS_COLORS = { published: "green", pending: "orange", draft: "gray", default: "blue", } as const; const StyledBadge = ({ value }: { value: string }) => ( <div style={{ backgroundColor: STATUS_COLORS[value as keyof typeof STATUS_COLORS] || STATUS_COLORS.default, padding: "4px 8px", borderRadius: "4px", color: "white", }} > {value} </div> ); const getHtmlElement = (children: React.ReactNode) => { const element = document.createElement("div"); const root = createRoot(element); root.render(children); return element; }; const allData = new Array(1000).fill(0).map((_, index) => { return { id: index + 1, title: `Post #${index + 1}`, status: ["published", "pending", "draft"][Math.floor(Math.random() * 3)], visits: Math.ceil(Math.random() * 1000), createdAt: new Date(Date.now() + index * 47 * 60 * 60 * 1000), }; }); const App = () => { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); const [data, setData] = useState<typeof allData>(allData.slice(0, pageSize)); const [loading, setLoading] = useState(false); const [SortingStates, setSortingStates] = useState<SortingState>([]); const [selectedRows, setSelectedRows] = useState<string[]>([]); const fetchData = async (page: number, size: number, SortingStates: SortingState = []) => { return new Promise<typeof allData>((resolve) => setTimeout(() => { if (SortingStates[0]) { allData.sort((a, b) => { const key = SortingStates[0].id as keyof (typeof allData)[0]; return (a[key] > b[key] ? 1 : -1) * (SortingStates[0].desc ? -1 : 1); }); } resolve(allData.slice(page * size, (page + 1) * size)); }, 750) ); }; return ( <div> <main> <OlTable loading={loading} paginationMode="server" paginationType="pages" pagination={{ pageIndex, pageSize, pageCount: Math.ceil(allData.length / pageSize), }} sortingMode="server" selectionMode="multiple" columns={[ { accessorKey: "id", size: 50 }, { accessorKey: "title", size: 50 }, { accessorKey: "visits", size: 50 }, { accessorKey: "status", cell: (info) => getHtmlElement(<StyledBadge value={info.getValue() as string} />), }, { accessorKey: "createdAt" }, ]} data={data} onOlPaginate={async ({ detail: { pageIndex, pageSize } }) => { setLoading(true); setPageIndex(pageIndex); setPageSize(pageSize); setData(await fetchData(pageIndex, pageSize, SortingStates)); setLoading(false); }} onOlColumnSort={async ({ detail }) => { setLoading(true); setSortingStates(detail as SortingState); setData(await fetchData(pageIndex, 10, SortingStates as SortingState)); setLoading(false); }} onOlRowSelect={({ detail: rows }) => { setSelectedRows(Object.keys(rows)); }} ></OlTable> <p>Selected rows: {selectedRows.join(", ")}</p> </main> </div> ); }
Importing
If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.
To import this component from the CDN using a script tag:
<script type="module" src="https://cdn.onlive.site/@onlive.site/ui@1.8.20/cdn/components/table/table.js"></script>
To import this component from the CDN using a JavaScript import:
import 'https://cdn.onlive.site/@onlive.site/ui@1.8.20/cdn/components/table/table.js';
To import this component using a bundler:
import '@onlive.site/ui/dist/components/table/table.js';
To import this component as a React component:
import OlTable from '@onlive.site/ui/dist/react/table';
Properties
Name | Description | Reflects | Type | Default |
---|---|---|---|---|
loading
|
The loading state. |
boolean
|
false
|
|
debug
|
Enable table debugging for development purpose. |
boolean
|
false
|
|
columns
|
The array of column defs to use for the table. |
ColumnDef
|
[]
|
|
data
|
The data for the table to display. Columns can access this data via string/index or a functional
accessor. When the data option changes reference, the table will reprocess the data.
|
unknown[]
|
[]
|
|
paginationMode
pagination-mode
|
The pagination mode. |
PaginationMode
|
'client'
|
|
paginationType
pagination-type
|
The pagination type. |
PaginationType
|
'pages'
|
|
pagination
|
The pagination state. |
PaginationState
|
- | |
selectionMode
selection-mode
|
The selection mode. |
SelectionMode
|
- | |
sortingMode
sorting-mode
|
The sorting mode. |
SortingMode
|
- | |
sorting
|
The sorting state. |
SortingState
|
[]
|
|
sortingRemoval
sorting-removal
|
Use the sorting removal step. |
boolean
|
true
|
|
rowSelection
row-selection
|
Use the sorting removal step. |
Record
|
{}
|
|
updateComplete |
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Events
Name | React Event | Description | Event Detail |
---|---|---|---|
ol-paginate |
onOlPaginate |
Emitted when the table is paginated. |
{ pageIndex: number, pageSize: number }
|
ol-row-select |
onOlRowSelect |
Emitted when a row is selected. |
{ rowSelection: Record<string, boolean> }
|
ol-column-sort |
onOlColumnSort |
Emitted when a column is sorted. |
{ sortFields: { desc: boolean; id: string; }[] }
|
Learn more about events.
Custom Properties
Name | Description | Default |
---|---|---|
--ol-table-head-background-color |
Table head background color. | |
--ol-table-head-spacing |
Table head spacing. | |
--ol-table-cell-spacing |
Table cell spacing. | |
--ol-table-cell-line-height |
Table cell line height. | |
--ol-table-cell-font-size |
Table cell font size. |
Learn more about customizing CSS custom properties.
Parts
Name | Description |
---|---|
base |
The component’s base wrapper. |
scroll |
The component’s scroll. |
table |
The component’s table. |
head |
The component’s table head. |
body |
The component’s table body. |
footer-actions |
The component’s table footer actions. |
Learn more about customizing CSS parts.
Dependencies
This component automatically imports the following dependencies.
<ol-button>
<ol-checkbox>
<ol-icon>
<ol-icon-button>
<ol-option>
<ol-popup>
<ol-progress-bar>
<ol-select>
<ol-spinner>
<ol-tag>