Upgrading from v11 or v12? Check out our upgrade guide for help on how to migrate to the updated API.
Upgrading from v10? Check out our v10 to v13 upgrade guide for help on how to migrate to the updated API.
yarn add @leafygreen-ui/[email protected]
npm install @leafygreen-ui/[email protected]
A basic table displays data in rows and columns without any additional functionality.
import {
Cell,
HeaderCell
HeaderRow,
Row,
Table,
TableBody,
TableHead,
} from '@leafygreen-ui/table';
<Table>
<TableHead>
<HeaderRow>
<HeaderCell>First</HeaderCell>
<HeaderCell>Second</HeaderCell>
<HeaderCell>Third</HeaderCell>
</HeaderRow>
</TableHead>
<TableBody>
{data.map((row: { [key: string]: any }) => (
<Row key={row.id}>
{Object.keys(row).map((cellKey: string, index: number) => {
return <Cell key={`${cellKey}-${index}`}>{row[cellKey]}</Cell>;
})}
</Row>
))}
</TableBody>
</Table>;
The useLeafyGreenTable
hook provides a custom integration with the @tanstack/react-table
library to manage advanced table behavior such as sorting, expanding, and rendering rows dynamically. It builds on @tanstack/react-table
's useReactTable
hook, adding LeafyGreen-specific configurations and integrations for seamless use with LeafyGreen's Table
components.
Although all react-table
features are supported using LeafyGreen Table, only the following features are styled according to design system guidelines:
- Sub rows
- Expandable rows
- Selectable rows
- Sortable rows
- Sticky row header
Usage with LeafyGreen Table components:
import {
Cell,
flexRender
HeaderCell
HeaderRow,
Row,
Table,
TableBody,
TableHead,
useLeafyGreenTable,
} from '@leafygreen-ui/table';
// Data that should be passed to the `useLeafyGreenTable` hook.
const [data] = useState(() => makeKitchenSinkData(200));
// Column definition
const columns = React.useMemo<Array<LGColumnDef<KitchenSink>>>(
() => [
{
accessorKey: 'rowOne',
header: 'Row One',
},
{
accessorKey: 'rowTwo',
header: 'Row Two',
},
{
accessorKey: 'rowThree',
header: 'Row Three',
},
],
[],
);
// Table instance
const table = useLeafyGreenTable<KitchenSink>({
data,
columns,
});
// Rows returned from the table instance
const { rows } = table.getRowModel();
return (
<Table table={table}>
<TableHead>
// Mapping through header rows
{table
.getHeaderGroups()
.map((headerGroup: HeaderGroup<KitchenSink>) => (
<HeaderRow key={headerGroup.id}>
// Mapping through header cells
{headerGroup.headers.map((header, index) => {
return (
<HeaderCell
key={header.id}
header={header}
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</HeaderCell>
);
})}
</HeaderRow>
))}
</TableHead>
<TableBody>
{rows.map((row: LeafyGreenTableRow<KitchenSink>) => {
// Checks if row is expandedContent
const isExpandedContent = row.isExpandedContent ?? false;
return (
<Fragment key={row.id}>
{!isExpandedContent && (
// row is required
<Row row={row}>
// Maps through visible cells
{row.getVisibleCells().map(cell => {
return (
// cell is required
<Cell key={cell.id} id={cell.id} cell={cell}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Cell>
);
})}
</Row>
)}
{isExpandedContent && <ExpandedContent row={row} />}
</Fragment>
);
})}
</TableBody>
</Table>
)
The useLeafyGreenTable
hook expects data in the form of an array of objects, where each object represents a row in the table. Each property of the object corresponds to a column in the table. Here’s a breakdown of the key requirements for the data:
-
Rows: Each row is an object containing key-value pairs.
- Key: Corresponds to the column’s
accessorKey
defined in the column configuration. - Value: The data displayed in the cell for that row and column. Example:
const data = [ { id: 1, firstName: 'Alice', lastName: 'Smith', age: 30 }, { id: 2, firstName: 'Bob', lastName: 'Johnson', age: 25 }, ];
- Key: Corresponds to the column’s
-
SubRows: Are used to represent nested rows within a parent row. This is useful for hierarchical data where each row can have child rows. The
data
can include asubRows
key in each object. This key holds an array of child rows for that specific row.Example:
const data = [ { id: 1, firstName: 'Alice', lastName: 'Smith', age: 30, subRows: [{ id: 11, firstName: 'Anna', lastName: 'Smith', age: 5 }], }, ];
-
ExpandedContent: Is used to display additional content when a row is expanded. This content is not necessarily a nested row but can be any additional information related to the row.
Example:
const SampleExpandedContent = (row: LeafyGreenTableRow<unknown>) => { return ( <div> <h4>Expanded Content for Row {row.id}</h4> <p>Additional details about this row:</p> <pre>{JSON.stringify(row.original, null, 2)}</pre> </div> ); }; const data = [ { id: 1, name: 'Parent Row', subRows: [ { id: 2, name: 'Child Row 1' }, { id: 3, name: 'Child Row 2' }, ], renderExpandedContent: SampleExpandedContent, }, ];
Data passed to useLeafyGreenTable
MUST have a stable reference to ensure optimal performance and avoid unnecessary re-renders. Internally, useReactTable
relies on reference equality for state updates. If the reference changes frequently, the hook might assume the data has been modified, triggering expensive updates. Changes to the data should explicitly signal an update. Stable references allow React to detect when actual changes occur versus unnecessary re-renders.
Example:
const fallbackData = []
export default function MyComponent() {
//✅ GOOD: This will not cause an infinite loop of re-renders because `columns` is a stable reference
const columns = useMemo(() => [
// ...
], []);
//✅ GOOD: This will not cause an infinite loop of re-renders because `data` is a stable reference
const [data, setData] = useState(() => [
// ...
]);
// Columns and data are defined in a stable reference, will not cause infinite loop!
const table = useReactTable({
columns,
data ?? fallbackData, //also good to use a fallback array that is defined outside of the component (stable reference)
});
return <table>...</table>;
}
React.useState
and React.useMemo
are not the only ways to give your data a stable reference. You can also define your data outside of the component or use a 3rd party state management library.
The main thing to avoid is defining the data array inside the same scope as the useReactTable call. That will cause the data array to be redefined on every render, which will cause an infinite loop of re-renders.
For more information check out TanStack's docs on giving data a stable reference.
The columns configuration is an array of objects, where each object defines how a column behaves and renders. It uses the @tanstack/react-table
column definitions and might include:
accessorKey
: The key in the data object to use for that column.header
: A string or function to define the column header.cell
: A function for custom cell rendering.- Other options like
enableSorting
,size
, oraccessorFn
for computed values. Checkout TanStack's docs on column definitions for more information. Example:const columns = [ { accessorKey: 'id', header: 'ID', size: 50 }, { accessorKey: 'firstName', header: 'First Name' }, { accessorKey: 'lastName', header: 'Last Name' }, { accessorKey: 'age', header: 'Age', size: 50, enableSorting: true }, ];
useLeafyGreenTable
also exposes all table options used in react-table
and by default, useLeafyGreenTable
includes a few of those options:
const [expanded, setExpanded] = useState < ExpandedState > {};
const table =
useReactTable <
LGTableDataType <
T >>
{
state: {
expanded,
...rest.state,
},
data,
columns,
getCoreRowModel: getCoreRowModel(),
getRowCanExpand: row => {
return !!row.original.renderExpandedContent || !!row.subRows?.length;
},
enableExpanding: true,
enableSortingRemoval: hasSortableColumns ? true : undefined,
getSubRows: row => row.subRows,
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: withPagination
? getPaginationRowModel()
: undefined,
onExpandedChange: setExpanded,
getExpandedRowModel: getLGExpandedRowModel(),
...rest,
};
state
: The state object for the tableexpanded
: The current expanded state of the rows.
getCoreRowModel
: returns a basic row model that is just a 1:1 mapping of the original data passed to the table.getSortedRowModel
: returns a row model that has had sorting applied to it.getPaginationRowModel
: returns a row model that only includes the rows that should be displayed on the current page based on the pagination state.getExpandedRowModel
: returns a custom row model that accounts for expandedContent and sub-rows.getRowCanExpand
: override the default behavior of determining whether a row can be expanded.enableExpanding
: enable expanding of all rowsenableSortingRemoval
: control the ability to remove sorting from a columngetSubRows
: used to access the sub rows for any given rowonExpandedChange
: called when the expanded table state changes
For other optional options check out the useLeafyGreenTable
prop table below.
The useLeafyGreenTable
hook returns an object that extends the Table object from react-table
with additional properties specific to LeafyGreen:
getRowModel
: Returns the an array with all rows, in addition to expanded subrows and expanded content. Subrows and expandedContent that are not expanded are not returned.hasSelectableRows
: A boolean indicating whether the table has selectable rows.- For more methods and properties available on the table object, refer to TanStack's table API documentation.
The useLeafyGreenVirtualTable
hook integrates virtualization into the LeafyGreen table by combining useVirtualizer
from @tanstack/react-virtual
with useLeafyGreenTable
. It processes table data while optimizing rendering for large datasets by rendering only visible rows.
The primary differences between useLeafyGreenTable
and useLeafyGreenVirtualTable
include the following:
- Extension of Base Hook:
useLeafyGreenVirtualTable
builds onuseLeafyGreenTable
to include virtual scrolling. - Efficient Rendering: Utilizes the
@tanstack/react-virtual
library for optimized rendering of large datasets. - Container Reference: Requires a
containerRef
for the scrolling container. - Virtual Properties: Adds a
virtual
object to the returned table model, exposing properties and methods from the virtualizer for managing virtualized rows.
The options passed to useLeafyGreenVirtualTable
are the same as those passed to useLeafyGreenTable
, with the addition of properties specific to virtualization, such as a required containerRef
and optional virtualizer configuration options from Tanstack Virtual.
Usage with LeafyGreen Table
components:
import {
Cell,
flexRender
HeaderCell
HeaderRow,
Row,
Table,
TableBody,
TableHead,
useLeafyGreenVirtualTable,
} from '@leafygreen-ui/table';
const tableContainerRef = React.useRef<HTMLDivElement>(null);
const [data] = useState(() => makeKitchenSinkData(10_000));
const virtualScrollingContainerHeight = css`
height: calc(100vh - 200px);
`;
const columns = React.useMemo<Array<LGColumnDef<KitchenSink>>>(
() => [
{
accessorKey: 'rowOne',
header: 'Row One',
},
{
accessorKey: 'rowTwo',
header: 'Row Two',
},
{
accessorKey: 'rowThree',
header: 'Row Three',
},
],
[],
);
const table = useLeafyGreenVirtualTable<KitchenSink>({
containerRef: tableContainerRef,
data,
columns,
virtualizerOptions: {
estimateSize: () => 50,
overscan: 10,
}
});
return (
<Table
table={table}
ref={tableContainerRef}
className={virtualScrollingContainerHeight}
>
<TableHead>
{table
.getHeaderGroups()
.map((headerGroup: HeaderGroup<KitchenSink>) => (
<HeaderRow key={headerGroup.id}>
{headerGroup.headers.map((header, index) => {
return (
<HeaderCell
key={header.id}
header={header}
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</HeaderCell>
);
})}
</HeaderRow>
))}
</TableHead>
<TableBody>
{table.virtual.getVirtualItems() &&
table.virtual
.getVirtualItems()
.map(
(
virtualRow: LeafyGreenVirtualItem<KitchenSink>,
index: number,
) => {
const row = virtualRow.row;
const isExpandedContent = row.isExpandedContent ?? false;
return (
<Fragment key={virtualRow.key}>
{!isExpandedContent && (
// row and virtualRow is required
<Row
row={row}
virtualRow={virtualRow}
data-row-index={index}
>
{row
.getVisibleCells()
.map((cell: LeafyGreenTableCell<KitchenSink>) => {
return (
// cell is required
<Cell key={cell.id} cell={cell}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Cell>
);
})}
</Row>
)}
{isExpandedContent && (
<ExpandedContent row={row} virtualRow={virtualRow} />
)}
</Fragment>
);
},
)}
</TableBody>
</Table>
)
By default, useLeafyGreenVirtualTable
passes the following defaults to the useVirtulizer
hook:
const table = useLeafyGreenTable({
...rest,
});
const { rows } = table.getRowModel();
const _virtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => containerRef.current,
estimateSize: () => 40,
overscan: 20,
...virtualizerOptions,
});
count
: The total number of items to virtualize.getScrollElement
: A function that returns the scrollable element for the virtualizer. It may return null if the element is not available yet.estimateSize
: This function is passed the index of each item and should return the actual size (or estimated size if you will be dynamically measuring items with virtualItem.measureElement) for each item. This measurement should return either the width or height depending on the orientation of your virtualizer.overscan
: The number of items to render above and below the visible area. Increasing this number will increase the amount of time it takes to render the virtualizer, but might decrease the likelihood of seeing slow-rendering blank items at the top and bottom of the virtualizer when scrolling.
You can override any of these defaults in the useLeafyGreenVirtualTable
hook with any of these options from TanStack's virtualizer options docs.
The useLeafyGreenVirtualTable
hook returns an object that extends the useLeafyGreenTable
object with additional properties for virtual scrolling:
virtual
: An object containing properties and methods from the virtualizer instance, including a customgetVirtualItems
method that maps virtual items to rows.getVirtualItems
: used to retrieve the virtualized items, mapping them to the corresponding rows in the table. This method ensures that only the visible rows are rendered, which improves performance when dealing with large datasets.- For more methods and properties available on the virtualizer instance, refer to TanStack's virtualizer instance docs.
Headers are returned from the useLeafyGreenTable
and useLeafyGreenVirtualTable
instances with the getHeaderGroups()
function. The getHeaderGroups
function is used to retrieve all header groups for a table. It returns an array of HeaderGroup
objects. For more information, check out Tanstack's documentation on HeaderGroups.
Example:
const table = useLeafyGreenTable<any>({
data,
columns,
});
return(
...
<TableHead>
{table.getHeaderGroups().map((headerGroup: HeaderGroup<any>) => (
<HeaderRow key={headerGroup.id}>
{headerGroup.headers.map((header, index) => {
return (
<HeaderCell key={header.id} header={header}>
{flexRender(header.column.columnDef.header, header.getContext())}
</HeaderCell>
);
})}
</HeaderRow>
))}
</TableHead>
...
)
Rows returned from the useLeafyGreenTable
and useLeafyGreenVirtualTable
instances differ slightly:
Rows are accessed from the table
object using the getRowModel
method. In this case, the returned rows array includes only visible rows. Subrows that are not visible are excluded, but if a row is expanded, its corresponding subrows are included in the array. For more information on getRowModel
check out TanStack's documentation on row models.
Example:
const table = useLeafyGreenTable<any>({
data,
columns,
});
// Destructured from the row model and used to render the table body.
const { rows } = table.getRowModel();
return(
...
<TableBody>
{rows.map((row: LeafyGreenTableRow<any>) => {
return (
// row is required
<Row row={row} key={row.id}>
{row.getVisibleCells().map(cell => {
return (
// cell is required
<Cell key={cell.id} id={cell.id} cell={cell}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Cell>
);
})}
</Row>
);
})}
</TableBody>
...
)
In a virtual table, rows are retrieved using the getVirtualItems
method from the virtual property of the table object.
Example:
const table =
useLeafyGreenVirtualTable <
Person >
{
containerRef: tableContainerRef,
data,
columns,
};
const virtualItems = table.virtual.getVirtualItems();
<TableBody>
{virtualItems &&
virtualItems.map((virtualRow: LeafyGreenVirtualItem<Person>) => {
const row = virtualRow.row;
const cells = row.getVisibleCells();
return (
// row and virtualRow is required
<Row key={virtualRow.key} virtualRow={virtualRow} row={row}>
{cells.map((cell: LeafyGreenTableCell<Person>) => {
return (
// cell is required
<Cell key={cell.id} cell={cell}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Cell>
);
})}
</Row>
);
})}
</TableBody>;
Similar to the example above, rows are accessed from the table
object using the getRowModel
method. However, when expanded content is included in the rows returned form the getRowModel
method, rows needs to be conditionally rendered:
- For each row, the
isExpandedContent
property is checked to determine if the row is an expanded content row. - If isExpandedContent is
false
, the row is rendered normally with its visible cells. - If isExpandedContent is
true
, the ExpandedContent component is rendered, passing the row as a prop.
Example:
const table =
useLeafyGreenTable <
any >
{
data,
columns,
};
// Destructured from the row model and used to render the table body.
const { rows } = table.getRowModel();
<TableBody>
{rows.map((row: LeafyGreenTableRow<Person>) => {
// Expanded content check
const isExpandedContent = row.isExpandedContent ?? false;
return (
<Fragment key={row.id}>
{!isExpandedContent && (
// row is required
<Row row={row}>
{row.getVisibleCells().map(cell => {
return (
// cell is required
<Cell key={cell.id} id={cell.id} cell={cell}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Cell>
);
})}
</Row>
)}
// row is required
{isExpandedContent && <ExpandedContent row={row} />}
</Fragment>
);
})}
</TableBody>;
Similar to the useLeafyGreenTable
example above except in a virtual table, rows are retrieved using the getVirtualItems
method from the virtual property of the table object.
Example:
const table =
useLeafyGreenVirtualTable <
Person >
{
containerRef: tableContainerRef,
data,
columns,
};
// Virtual rows
const virtualItems = table.virtual.getVirtualItems();
<TableBody>
{virtualItems &&
virtualItems.map((virtualRow: LeafyGreenVirtualItem<KitchenSink>) => {
const row = virtualRow.row;
// Expanded content check
const isExpandedContent = row.isExpandedContent ?? false;
return (
// note: the key should be virtualRow.key not row.id
<Fragment key={virtualRow.key}>
{!isExpandedContent && (
// row and virtualRow is required
<Row row={row} virtualRow={virtualRow}>
{row
.getVisibleCells()
.map((cell: LeafyGreenTableCell<KitchenSink>) => {
return (
<Cell key={cell.id} cell={cell}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Cell>
);
})}
</Row>
)}
{isExpandedContent && (
// row and virtualRow is required
<ExpandedContent row={row} virtualRow={virtualRow} />
)}
</Fragment>
);
})}
</TableBody>;
Since rows and expanded subrows are returned in the same hierarchy within the row object, a depth check is often necessary to distinguish whether a row is a subrow. This can typically be done using the depth
property included in the row object, which indicates its nesting level within the hierarchy. If the depth is greater than 0
, then it is a subrow.
<TableBody>
{rows.map((row: LeafyGreenTableRow<Person>) => {
const isExpandedContent = row.isExpandedContent ?? false;
// depth check
const depth = row.depth ?? 0;
return (
<Fragment key={row.id}>
{!isExpandedContent && (
// row is required
// Different styling for a subrow
<Row
row={row}
className={cx(css`
background: ${depth === 1 ? 'white' : 'whitesmoke'};
`)}
>
{row.getVisibleCells().map(cell => {
return (
// cell is required
<Cell key={cell.id} id={cell.id} cell={cell}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
// Additional text for a subrow
{depth === 1 && 'Subrow'}
</Cell>
);
})}
</Row>
)}
// row is required
{isExpandedContent && <ExpandedContent row={row} />}
</Fragment>
);
})}
</TableBody>
Sorting can be applied within the column definitions:
const columns = [
{
header: () => 'Name',
accessorKey: 'name',
sortingFn: 'alphanumeric', // use built-in sorting function by name
},
{
header: () => 'Age',
accessorKey: 'age',
sortingFn: 'myCustomSortingFn', // use custom global sorting function
},
{
header: () => 'Birthday',
accessorKey: 'birthday',
sortingFn: 'datetime', // recommended for date columns
},
{
header: () => 'Profile',
accessorKey: 'profile',
// use custom sorting function directly
sortingFn: (rowA, rowB, columnId) => {
return rowA.original.someProperty - rowB.original.someProperty;
},
},
{
header: () => 'Color',
accessorKey: 'color',
sortDescFirst: true, //sort by color in descending order first (default is ascending for string columns)
},
];
Be default, sorting is disabled, but you can enable sorting by setting enableSorting: true
.
{
accessorKey: 'mdbVersion',
header: 'MongoDB Version',
enableSorting: true,
size: 90,
},
For more information on sorting, check out TanStack's documentation on sorting.
By default, LeafyGreen Table
uses table-layout: auto
. This CSS property sets the algorithm used to lay out <table>
cells, rows, and columns. When a table-layout
is set to auto
this means that the widths of the table and its cells are adjusted to fit the content, which is the default in most browsers.
You can specify column widths using the size
property in your column definitions:
const columns = [
{
accessorKey: 'col1',
size: 270, //set column size for this column
},
//...
];
The width is applied to the corresponding <th>
element, but in auto
layout, it may not always be respected as columns adjust to content. If you want the width to always be respected, there are a few recommendations:
- Add
min-width
toHeaderCell
: Prevent the header from shrinking below a minimum width.<HeaderCell key={header.id} header={header} className={cx({ [css` // since the table is not fixed, the width is not respected. This prevents the width from getting any smaller. min-width: 120px; `]: index === 5, })} >
- Use
table-layout: fixed
: Withfixed
, column widths are based only on the table’s width and specified column sizes. This approach ensures consistent widths but sacrifices responsiveness.
For tables with virtual scrolling and truncation disabled, table-layout
is set to fixed
by default to prevent row height shifts due to columns widths changing during scrolling. Without this, scrolling could cause layout issues and application crashes.
To maintain some responsiveness, mix fixed and auto column widths:
const columns = [
{
accessorKey: 'col1',
size: 200, //set column size for this column
},
{
accessorKey: 'col2',
size: 70, //set column size for this column
},
{
accessorKey: 'col3',
size: NaN, //set column size to `auto`
},
];
Limitations: In table-layout: fixed
, columns with auto
widths do not support min-width
, so they might shrink excessively on small viewports.
@leafygreen-ui/table
exports:
- LeafyGreen table components
- LeafyGreen table hooks
- All exports from
@tanstack/react-table
- Test utils (README link)
- TypeScript types
All exports can be found here.
Name | Description | Type | Default |
---|---|---|---|
table |
Object returned from the useLeafyGreenTable or useLeafyGreenVirtualTable hook |
'LeafyGreenTable<T>' | 'LeafyGreenVirtualTable<T>' |
- |
shouldAlternateRowColor |
Determines whether alternating rows will have dark backgrounds | boolean |
false |
shouldTruncate |
Whether all rows will truncate. If true, cells will truncate at one line. If false then there will be no height limit and cells will not truncate. | boolean |
true |
verticalAlignment |
When rows are not truncated, this will determine if cells should be top or middle aligned | 'top' | 'bottom' |
top |
baseFontSize |
The base font size of the title and text rendered in children | '13' | '16' |
13 |
darkMode |
Render the component in dark mode. | boolean |
false |
+ other HTML table
element props
Name | Description | Type | Default |
---|---|---|---|
isSticky |
Determines whether the table head will stick as the user scrolls down. | boolean |
false |
+ other HTML thead
element props
All HTML tr
element props
Name | Description | Type | Default |
---|---|---|---|
header |
Header object returned from the useLeafygreenTable hook. |
Header<T, any> |
- |
+ other HTML th
element props
TableBody
accepts HTML tbody
element props.
Name | Description | Type | Default |
---|---|---|---|
disabled |
Determines whether the row is disabled | boolean |
false |
row |
Row object passed from the useLeafygreenTable or useLeafyGreenVirtualTable hook. Required if using the useLeafyGreenTable or useLeafyGreenVirtualTable hooks. |
LeafygreenTableRow<T> |
- |
virtualRow |
Virtual row object passed from the useLeafyGreenVirtualTable hook. Required if using the useLeafyGreenVirtualTable hooks. |
VirtualItem |
- |
+ other HTML tr
element props
Name | Description | Type | Default |
---|---|---|---|
cell |
The cell object that is returned when mapping through a row passed from the useLeafyGreenTable or useLeafyGreenVirtualTable hook. Required if using the useLeafyGreenTable or useLeafyGreenVirtualTable hooks. |
LeafyGreenTableCell<T> |
- |
+ other HTML td
element props.
Name | Description | Type | Default |
---|---|---|---|
data |
Data in the form of an array of objects, where each object represents a row in the table. Each property of the object corresponds to a column in the table. | TableOptions<LGTableDataType<T>> |
- |
columns |
The columns configuration is an array of objects, where each object defines how a column behaves and renders. | TableOptions<LGTableDataType<T>> |
- |
hasSelectableRows |
Setting this prop will inject a new column containing a checkbox into all rows. | boolean |
false |
withPagination |
Setting this prop will indicate that the Table component is being used with the Pagination component. This will expose various pagination utilities from table.getState().pagination . For more information, check out TanStack's pagination documentation on pagination. |
boolean |
false |
allowSelectAll |
This prop controls whether a 'select all' checkbox will be rendered in the header row. This will be set to true by default. |
boolean |
true |
Name | Description | Type | Default |
---|---|---|---|
containerRef |
A required ref to the <div> wrapping <table> |
RefObject<HTMLElement> |
- |
data |
Data in the form of an array of objects, where each object represents a row in the table. Each property of the object corresponds to a column in the table. | TableOptions<LGTableDataType<T>> |
- |
columns |
The columns configuration is an array of objects, where each object defines how a column behaves and renders. | TableOptions<LGTableDataType<T>> |
- |
hasSelectableRows |
Setting this prop will inject a new column containing a checkbox into all rows. | boolean |
false |
allowSelectAll |
This prop controls whether a 'select all' checkbox will be rendered in the header row. This will be set to true by default. |
boolean |
true |
virtualizerOptions |
Available TanStack virtualizer options to pass to the virtualizer instance |
getTestUtils()
is a util that allows consumers to reliably interact with LG Table
in a product test suite. If the Table
component cannot be found, an error will be thrown.
import { Table, getTestUtils } from '@leafygreen-ui/table';
const utils = getTestUtils(lgId?: string); // lgId refers to the custom `data-lgid` attribute passed to `Table`. It defaults to 'lg-table' if left empty.
import { render } from '@testing-library/react';
import { Table, getTestUtils } from '@leafygreen-ui/table';
...
test('table', () => {
render(<Table>...</Table>);
const { getAllVisibleRows } = getTestUtils();
expect(getAllVisibleRows().length).toEqual(3);
});
import { render } from '@testing-library/react';
import { Table, getTestUtils } from '@leafygreen-ui/table';
...
test('returns the correct rows', () => {
render(
<>
<Table>...</Table>
<Table data-lgid="lg-table-2">...</Table>
</>,
);
// First Table
const { getAllVisibleRows } = getTestUtils();
expect(getAllVisibleRows().length).toEqual(3);
// Second Table
const { getAllVisibleRows: getAllVisibleRowsB } = getTestUtils('lg-table-2');
expect(getAllVisibleRowsB().length).toEqual(4);
});
const {
getTable,
getAllHeaders,
getHeaderByIndex: (index: number) => { getElement, getSortIcon },
getSelectAllCheckbox,
getAllVisibleRows,
getRowByIndex: (index: number) => {
getElement,
getAllCells,
getCheckbox,
getExpandButton,
isExpanded,
isSelected,
isDisabled,
},
getAllVisibleSelectedRows,
} = getTestUtils();
Util | Description | Returns |
---|---|---|
getTable() |
Returns the table node or null if the table node is not found. |
HTMLTableElement |
getAllHeaders() |
Returns an array of <th> (<HeaderCell> ) in the DOM. Throws if there are no elements. |
Array<HTMLTableCellElement> |
getHeaderByIndex(index: number) |
Returns utils for an individual <th> (<HeaderCell> ) in the DOM |
HeaderUtils | null |
getSelectAllCheckbox() |
Returns the input node for the select all checkbox or null |
HTMLInputElement | null |
getAllVisibleRows() |
Returns an array of all visible <tr> (<Row> ) in the DOM. Throws if there are no elements. |
Array<HTMLTableRowElement> |
getRowByIndex(index: number) |
Returns utils for an indivudial <tr> (<Row> ) in the DOM |
RowUtils | null |
getAllVisibleSelectedRows |
Returns an array of all visible selected <tr> (<Row> ) in the DOM |
Array<HTMLTableRowElement> |
HeaderUtils | Description | Returns |
---|---|---|
getElement() |
Returns the <th> element |
HTMLTableCellElement |
getSortIcon() |
Returns the sort button or null |
HTMLButtonElement | null |
RowUtils | Description | Returns |
---|---|---|
getElement() |
Returns the <tr> (<HeaderCell> ) element |
HTMLTableRowElement |
getAllCells() |
Returns an array with all the <td> (<Cell> ) elements in the row |
Array<HTMLTableCellElement> |
getCheckbox() |
Returns the input element or null |
HTMLInputElement | null |
getExpandButton() |
Returns the expand button element or null |
HTMLButtonElement | null |
isExpanded() |
Returns if the <tr> (<Row> ) is expanded |
boolean |
isSelected() |
Returns if the <tr> (<Row> ) is selected |
boolean |
isDisabled() |
Returns if the <tr> (<Row> ) is disabled |
boolean |
- Basic
- Styled components
- Sticky header
useLeafyGreenTable
- Only rows
- Rows and subrows
- Expanded content
- Row, subrows, and expanded content
- With extra custom columns
- No Truncation
- Zebra Stripes
- Sortable rows
- Selectable rows
- Selectable rows with no select all
- Disabled rows
- With pagination
useLeafyGreenVirtualTable
- Only rows
- Rows and subrows
- Expanded content
- Rows, subrows, and expanded content
- With extra custom columns
- No Truncation
- Zebra Stripes
- Sortable rows
- Selectable rows
- Selectable rows with no select all
- Disabled rows