Skip to content

Table

Show design guidelines

Use certara-table to easily build out static tables with support for search, sort, and pagination. This component is built off of Grid.js.

As a cautionary note, this component is best used for static table. If the data within the table changes frequently (by user action, or async request, etc.) this component may not be the most performant. This is due to the way Grid.js re-renders the table when the data changes. In order to change the data in a cell, the entire table needs to be re-rendered to calculate the height and width of the table and all of its cells. The best use case for this component is a drop in replacement for datatables.

HTML React Angular
Study Project Licenses Actions
ABC-123 ABC 2 Edit
ABC-456 ABC 10 Edit
DEF-123 DEF 102 Edit
<certara-table full-height="false" sort="true">
<table>
<thead>
<tr>
<th>Study</th>
<th>Project</th>
<th>Licenses</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>ABC-123</td>
<td>ABC</td>
<td>2</td>
<td>
<certara-link href="#">Edit</certara-link>
</td>
</tr>
<tr>
<td>ABC-456</td>
<td>ABC</td>
<td>10</td>
<td>
<certara-link href="#">Edit</certara-link>
</td>
</tr>
<tr>
<td>DEF-123</td>
<td>DEF</td>
<td>102</td>
<td>
<certara-link href="#">Edit</certara-link>
</td>
</tr>
</tbody>
</table>
</certara-table>
import { CertaraLink, CertaraTable } from '@certara/certara-ui-react';
<CertaraTable fullHeight={false} sort={true}>
<table>
<thead>
<tr>
<th>Study</th>
<th>Project</th>
<th>Licenses</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>ABC-123</td>
<td>ABC</td>
<td>2</td>
<td>
<CertaraLink href="#">Edit</CertaraLink>
</td>
</tr>
<tr>
<td>ABC-456</td>
<td>ABC</td>
<td>10</td>
<td>
<CertaraLink href="#">Edit</CertaraLink>
</td>
</tr>
<tr>
<td>DEF-123</td>
<td>DEF</td>
<td>102</td>
<td>
<CertaraLink href="#">Edit</CertaraLink>
</td>
</tr>
</tbody>
</table>
</CertaraTable>
// In your module (e.g., app.module.ts)
import { CertaraUiAngularModule } from '@certara/certara-ui-angular';
@NgModule({
imports: [CertaraUiAngularModule]
})
// In your template:
<certara-table full-height="false" sort="true">
<table>
<thead>
<tr>
<th>Study</th>
<th>Project</th>
<th>Licenses</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>ABC-123</td>
<td>ABC</td>
<td>2</td>
<td>
<certara-link href="#">Edit</certara-link>
</td>
</tr>
<tr>
<td>ABC-456</td>
<td>ABC</td>
<td>10</td>
<td>
<certara-link href="#">Edit</certara-link>
</td>
</tr>
<tr>
<td>DEF-123</td>
<td>DEF</td>
<td>102</td>
<td>
<certara-link href="#">Edit</certara-link>
</td>
</tr>
</tbody>
</table>
</certara-table>

When you use <CertaraTable> from @certara/certara-ui-react, you typically drive the grid with data and columns props instead of putting a static <table> like the above examples. To render React components inside cells, use a column formatter and wrap your JSX with the _() helper from gridjs-react.

ExampleTable
import {_} from 'gridjs-react';
import {faker} from '@faker-js/faker';
import {CertaraTable, CertaraButton, CertaraBadge, CertaraDropdown, CertaraDropdownItem, CertaraIcon, CertaraDropdownCheckbox} from '@certara/certara-ui-react';
const data = Array(25)
.fill()
.map(() => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
status: faker.helpers.arrayElement(['active', 'draft']),
}));
const columns = [
{
name: 'Name',
data: (row) => row.name,
search: true,
},
{
name: 'Status',
data: (row) => row.status,
formatter: (cell, row) => _(<CertaraBadge key={`status-${row.id}`}>{cell === 'active' ? 'Active' : 'Draft'}</CertaraBadge>),
search: true,
},
{
name: 'Actions',
sort: false,
formatter: (cell, row) =>
_(
<CertaraDropdown buttonVariant="link" showOpenerCaret={false}>
<CertaraIcon name="ellipsis" variant="solid" size="18" slot="button-label" />
<CertaraDropdownItem
value="open"
onCertaraDropdownItemClick={() => {
// handle open
}}>
Open
</CertaraDropdownItem>
<CertaraDropdownItem
value="delete"
className="text-danger"
onCertaraDropdownItemClick={() => {
// handle delete
}}>
Delete
</CertaraDropdownItem>
</CertaraDropdown>,
),
},
];
export function ExampleTable() {
return (
<CertaraTable data={data} columns={columns} fullHeight={false} resizable sort search pagination={{limit: 10}}>
<div slot="left-actions">
<CertaraButton
leftIcon="plus"
size="sm"
onCertaraClick={() => {
// handle create
}}>
Create
</CertaraButton>
</div>
<div slot="filters">
<CertaraIcon name="filter" variant="solid" className="text-gray-300" size="14" />
<CertaraDropdown buttonSize="sm">
<span slot="button-label">Status</span>
<CertaraDropdownCheckbox
checked={false}
onCertaraChange={(e) => {
// handle custom filter change
}}>
Draft
</CertaraDropdownCheckbox>
<CertaraDropdownCheckbox
checked={false}
onCertaraChange={(e) => {
// handle custom filter change
}}>
Active
</CertaraDropdownCheckbox>
</CertaraDropdown>
</div>
</CertaraTable>
);
}

Grid.js uses Preact to render the elements in the cells _ is the exposed Preact render function. This is what allows you to render custom JSX and react components within the grid.js formatters. Preact works almost identically to normal React. See the Grid.js docs for more information.

When applying custom jsx rendering in certara-table like the above example, there are two different “pieces” to consider: the presentation, and the searchable data.

What the user see’s is based on what the column’s formatter function returns, whether it is jsx, string, or anything else. This isn’t necissarily “the data inside of the cell” from a conceptual standpoint. That means, what is returned from the formatter function isn’t sortable, or searchable, it is purly presentation.

The data layer, or what is returned from the column’s data function, is what is used for sorting and searching. If you’d like your fancy react columns to have some specific, sortable and searchable data, you’ll need to return that from the column’s data function.

For an advanced usage example, see the TFL’s project

While data loads, show certara-skeleton-table in an absolutely positioned layer over the same area where the table will appear. Give the wrapper position-relative and a min-height so the skeleton has space before the real table mounts.

CertaraTableLoadingExample.jsx
import {useCallback, useState} from 'react';
import {CertaraButton, CertaraTable, CertaraSkeletonTable} from '@certara/certara-ui-react';
/** Simulates an API that returns table rows after a short delay */
function fetchRows() {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{id: '1', name: 'Alice Chen', role: 'Admin'},
{id: '2', name: 'Bob Smith', role: 'Editor'},
{id: '3', name: 'Carol Jones', role: 'Viewer'},
]);
}, 1200);
});
}
const columns = [
{name: 'Name', data: (row) => row.name, search: true},
{name: 'Role', data: (row) => row.role, search: true},
];
export function CertaraTableLoadingExample() {
const [rows, setRows] = useState(columns);
const [loading, setLoading] = useState(false);
const loadData = useCallback(() => {
setLoading(true);
fetchRows().then((data) => {
setRows(data);
setLoading(false);
});
}, []);
return (
<div>
<div className="mb-2">
<CertaraButton size="sm" disabled={loading} onCertaraClick={loadData}>
Reload data
</CertaraButton>
</div>
<div className="position-relative" style={{minHeight: '200px'}}>
{loading && (
<div>
<CertaraSkeletonTable className="position-absolute w-100 h-100" />
</div>
)}
{!loading && rows.length > 0 && (
<div className="pointer-events-auto animation-duration-500 fadeIn">
<CertaraTable data={rows} columns={columns} fullHeight={false} sort search />
</div>
)}
</div>
</div>
);
}

autoRefresh

Attributeauto-refresh
Typeboolean
Defaulttrue
Requiredfalse
DescriptionAutomatically refresh the table when the data prop changes

bordered

Attributebordered
Typeboolean
Defaultfalse
Requiredfalse
DescriptionPuts borders between table data cells

columns

Attributeundefined
Type(string | TableColumn)[]
Defaultundefined
Requiredfalse
DescriptionColumn names (strings) or column config objects. See https://gridjs.io/docs/config/columns. Set with JS when the component is used in an HTML context.

data

Attributeundefined
Typeany[]
Defaultundefined
Requiredfalse
DescriptionCan be an array of arrays, or an array of objects. This needs to be set with JS when the component is in an HTML context

fixedHeader

Attributefixed-header
Typeboolean
Defaultfalse
Requiredfalse
DescriptionFixed headers also require a set height

from

Attributeundefined
TypeHTMLTableElement
Defaultundefined
Requiredfalse
DescriptionReference to an existing HTML <table> element to use as the data source. GridJS will read the data from this table. Alternatively, place a <table> element as a child of <certara-table> and it will be auto-detected. See: https://gridjs.io/docs/examples/from

fullHeight

Attributefull-height
Typeboolean
Defaulttrue
Requiredfalse
DescriptionThe table container will stretch to the full height of the viewport

height

Attributeheight
Typestring
Defaultundefined
Requiredfalse
DescriptionSet height with CSS units (e.g. 400px)

offsetY

Attributeoffset-y
Typestring
Defaultundefined
Requiredfalse
DescriptionOffset to stretch table to fill available vertical space aside from reserved space for toolbars, etc. (e.g., 230px)

pagination

Attributepagination
Typeboolean | object
Defaultundefined
Requiredfalse
DescriptionSet to true to show pagination, configure extended options with the JS object (Docs)

resizable

Attributeresizable
Typeboolean
Defaultfalse
Requiredfalse
DescriptionAllows columns to be resized
Attributesearch
Typeboolean
Defaultfalse
Requiredfalse
DescriptionShows a built-in table filter search field

searchPlaceholder

Attributesearch-placeholder
Typestring
Default'Search'
Requiredfalse
DescriptionPlaceholder text for built-in table search input

sort

Attributesort
Typeboolean
Defaultfalse
Requiredfalse
DescriptionAllows simple sorting on columns. More complex data needs to have custom rules in the columns.sort.compare object

tableClassName

Attributetable-class-name
Typestring
Defaultundefined
Requiredfalse
DescriptionAdds a className specifically to the rendered <table> element vs. the component wrapper

There are no events available for this component

NameSignatureDescription
refresh() => Promise<void>Force a re-render of the table
NameDescription
Default slot for an optional HTML <table> element to use as the data source
filtersSlot for center-aligned toolbar content
left-actionsSlot for left-aligned toolbar content
right-actionsSlot for right-aligned toolbar content