useTable
This hook provides functionality to filter, sort, paginate and select rows of data for a Table component. This hook takes over the state management of the Table data and returns us a handful of variables to use.
Basic Usage
import { useTable } from '@krakentech/coral';
const { data } = useTable({ data: initialData });
<Table data={data} columns={columns} />| Name | Age | Address | Email address |
|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com |
| Name 3 | 42 | 3 Street Road, Town, City, Postcode | name3.152@myemail.org |
| Name 4 | 42 | 4 Street Road, Town, City, Postcode | name4.834@webmail.net |
| Name 5 | 42 | 5 Street Road, Town, City, Postcode | name5.611@example.com |
| Name 6 | 42 | 6 Street Road, Town, City, Postcode | name6.299@testmail.com |
Now that we’ve provided the Table component with the data given back to us from the hook, it’ll give us back a handful of helpful variables to play with.
Filtering
It’s possible to use a Coral TextField component to filter the results of a Table.
const initialData: TableColumnData[] = [
{
key: '1',
name: 'Name 1',
address: '1 Street Road, Town, City, Postcode',
age: 65,
},
...
];
const columns: TableColumn[] = [
{ title: 'Name', key: 'name' },
{ title: 'Age', key: 'age', align: 'center', },
{ title: 'Address', key: 'address', align: 'right' },
];
const { data, filterValue, handleFilterChange } = useTable({
data: initialData,
});
<Stack flexDirection="column" gap="lg">
<TextField
label="Filter table"
startIcon={<IconSearch size={16} />}
value={filterValue}
onChange={handleFilterChange}
/>
<Table data={data} columns={columns} />
</Stack>| Name | Age | Address | Email address |
|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com |
| Name 3 | 42 | 3 Street Road, Town, City, Postcode | name3.152@myemail.org |
| Name 4 | 42 | 4 Street Road, Town, City, Postcode | name4.834@webmail.net |
| Name 5 | 42 | 5 Street Road, Town, City, Postcode | name5.611@example.com |
| Name 6 | 42 | 6 Street Road, Town, City, Postcode | name6.299@testmail.com |
Sort
It’s possible to sort each column in a Table, alphabetically ascending / descending, by clicking on the column header. Passing sortable: true to the column configuration will enable this feature.
const initialData: TableColumnData[] = [
{
key: '1',
name: 'Name 1',
address: '1 Street Road, Town, City, Postcode',
age: 65,
},
...
];
const columns: TableColumn[] = [
{ title: 'Name', key: 'name' },
{ title: 'Age', key: 'age', sortable: true },
{ title: 'Address', key: 'address' },
];
const { data, sortValue, handleSortChange } = useTable({
data: initialData,
});
<Table
data={data}
columns={columns}
sortValue={sortValue}
handleSortChange={handleSortChange}
/>| Name | Address | Email address | |
|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com |
| Name 3 | 42 | 3 Street Road, Town, City, Postcode | name3.152@myemail.org |
| Name 4 | 42 | 4 Street Road, Town, City, Postcode | name4.834@webmail.net |
| Name 5 | 42 | 5 Street Road, Town, City, Postcode | name5.611@example.com |
| Name 6 | 42 | 6 Street Road, Town, City, Postcode | name6.299@testmail.com |
Custom Sort
You can provide a custom sorting function using the compareFn parameter. This allows you to define your own sorting logic.
For example, you could sort by numbers within a string as shown with the address column below.
const initialData: TableColumnData[] = [
{
key: '1',
name: 'Name 1',
address: '1 Street Road, Town, City, Postcode',
age: 65,
},
...
];
const columns: TableColumn[] = [
{ title: 'Name', key: 'name' },
{ title: 'Age', key: 'age', sortable: true },
{ title: 'Address', key: 'address', sortable: true },
];
const customCompareFn = (
valueA: any,
valueB: any,
sortOrder: 'asc' | 'desc' | 'none' = 'none'
) => {
if (valueA == null || valueB == null) {
return valueA == null ? (valueB == null ? 0 : 1) : -1;
}
const extractLeadingNumber = (str: string) => Number(str.match(/^(-?\d+)/)?.[0] ?? NaN);
const [strA, strB] = [String(valueA).trim(), String(valueB).trim()];
const [numA, numB] = [extractLeadingNumber(strA), extractLeadingNumber(strB)];
if (isNaN(numA) && isNaN(numB)) {
return sortOrder === 'asc' ? strA.localeCompare(strB) : strB.localeCompare(strA);
}
if (isNaN(numA)) {return sortOrder === 'asc' ? 1 : -1}
if (isNaN(numB)) {return sortOrder === 'asc' ? -1 : 1}
return sortOrder === 'asc' ? numA - numB : numB - numA;
};
const { data, sortValue, handleSortChange } = useTable({
data: initialData,
compareFn: customCompareFn,
});
<Table
data={data}
columns={columns}
sortValue={sortValue}
handleSortChange={handleSortChange}
/>| Name | |||
|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com |
| Name 3 | 42 | 3 Street Road, Town, City, Postcode | name3.152@myemail.org |
| Name 4 | 42 | 4 Street Road, Town, City, Postcode | name4.834@webmail.net |
| Name 5 | 42 | 5 Street Road, Town, City, Postcode | name5.611@example.com |
| Name 6 | 42 | 6 Street Road, Town, City, Postcode | name6.299@testmail.com |
Paginate
It’s possible to create pagination for a Table using a combination of useTable, plus other Coral components like Stack, Select, Button and Typography.
const initialData: TableColumnData[] = [
{
key: '1',
name: 'Name 1',
address: '1 Street Road, Town, City, Postcode',
age: 65,
},
...
];
const columns: TableColumn[] = [
{ title: 'Name', key: 'name' },
{ title: 'Age', key: 'age' },
{ title: 'Address', key: 'address' },
];
const {
data,
currentPage,
setNextPage,
setPreviousPage,
prevPageDisabled,
nextPageDisabled,
pageSelectValues,
handleSelectChange,
totalPages,
} = useTable({
data: initialData,
perPage: 2,
});
<Stack direction="vertical" gap="lg">
<Table data={data} columns={columns} />
<Stack gap="lg" alignItems="center">
<Button
onClick={() => setPreviousPage()}
size="small"
color="secondary"
disabled={prevPageDisabled}
>
<IconChevronLeft />
</Button>
<Typography>Page</Typography>
<Select
label="Page"
values={pageSelectValues}
value={{
label: currentPage.toString(),
value: currentPage,
}}
onChange={handleSelectChange}
/>
<Typography>of {totalPages}</Typography>
<Button
onClick={() => setNextPage()}
size="small"
color="secondary"
disabled={nextPageDisabled}
>
<IconChevronRight />
</Button>
</Stack>
</Stack>| Name | Age | Address | Email address |
|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com |
Page
of 1
Selectable rows
It’s possible to select all rows in the Table, or select individual rows.
const initialData: TableColumnData[] = [
{
key: '1',
name: 'Name 1',
address: '1 Street Road, Town, City, Postcode',
age: 65,
},
...
];
const columns: TableColumn[] = [
{ title: 'Name', key: 'name' },
{ title: 'Age', key: 'age' },
{ title: 'Address', key: 'address' },
];
const {
data,
rowsSelected,
allRowsSelected,
handleRowSelected,
handleAllRowsSelected,
} = useTable({
data: initialData,
});
<Table
data={data}
columns={columns}
rowsSelectable
rowsSelected={rowsSelected}
allRowsSelected={allRowsSelected}
handleRowSelected={handleRowSelected}
handleAllRowsSelected={handleAllRowsSelected}
/>| Name | Age | Address | Email address | |
|---|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com | |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com | |
| Name 3 | 42 | 3 Street Road, Town, City, Postcode | name3.152@myemail.org | |
| Name 4 | 42 | 4 Street Road, Town, City, Postcode | name4.834@webmail.net | |
| Name 5 | 42 | 5 Street Road, Town, City, Postcode | name5.611@example.com | |
| Name 6 | 42 | 6 Street Road, Town, City, Postcode | name6.299@testmail.com |
Full Example
It’s possible to combine all of these features together to give the user as much flexibility as possible with the Table component.
const initialData: TableColumnData[] = [
{
key: '1',
name: 'Name 1',
address: '1 Street Road, Town, City, Postcode',
age: 65,
},
...
];
const columns: TableColumn[] = [
{ title: 'Name', key: 'name' },
{ title: 'Age', key: 'age', sortable: true },
{ title: 'Address', key: 'address' },
];
const {
data,
currentPage,
setNextPage,
totalPages,
setPreviousPage,
pageSelectValues,
handleSelectChange,
filterValue,
handleFilterChange,
prevPageDisabled,
nextPageDisabled,
handleSortChange,
sortValue,
handleRowSelected,
handleAllRowsSelected,
allRowsSelected,
rowsSelected,
} = useTable({
data: initialData,
perPage: 4,
});
<Stack direction="vertical" gap="lg">
<TextField
label="Filter table"
startIcon={<IconSearch size={16} />}
value={filterValue}
onChange={handleFilterChange}
/>
<Table
data={data}
columns={columns}
handleSortChange={handleSortChange}
sortValue={sortValue}
rowsSelectable
handleAllRowsSelected={handleAllRowsSelected}
handleRowSelected={handleRowSelected}
rowsSelected={rowsSelected}
allRowsSelected={allRowsSelected}
/>
<Stack gap="lg" alignItems="center">
<Button
onClick={() => setPreviousPage()}
size="small"
color="secondary"
disabled={prevPageDisabled}
>
<IconChevronLeft />
</Button>
<Typography>Page</Typography>
<Select
label="Page"
values={pageSelectValues}
value={{
label: currentPage.toString(),
value: currentPage,
}}
onChange={handleSelectChange}
/>
<Typography>of {totalPages}</Typography>
<Button
onClick={() => setNextPage()}
size="small"
color="secondary"
disabled={nextPageDisabled}
>
<IconChevronRight />
</Button>
</Stack>
</Stack>| Name | Address | Email address | ||
|---|---|---|---|---|
| Name 1 | 32 | 1 Street Road, Town, City, Postcode | name1.483@testmail.com | |
| Name 2 | 42 | 2 Street Road, Town, City, Postcode | name2.927@example.com | |
| Name 3 | 42 | 3 Street Road, Town, City, Postcode | name3.152@myemail.org | |
| Name 4 | 42 | 4 Street Road, Town, City, Postcode | name4.834@webmail.net |
Page
of 1
Full API
Arguments
| Name | Description | type | Default value | Required |
|---|---|---|---|---|
data | The initial data given by the consumer | TableColumnData[] | undefined | true |
columns | The initial column data given by the consumer | TableColumn[] | undefined | false |
columnVisibility | An object listing whether columns should be visible or not | Record<string, boolean> | {} | false |
perPage | How many results to show per paginated page | number | 100 | false |
compareFn | A custom compare function for sorting | (a: any, b: any, sortOrder?: 'asc' , 'desc' , 'none') => number | undefined | false |
Return
| Name | Description | type |
|---|---|---|
data | The data to use with the Table data prop | TableColumnData[] |
columns | The column data to use with the Table columns prop | TableColumn[] |
currentPage | The current page of paginated data being displayed | number |
setCurrentPage | A callback function that sets the current page when paginated | (page: number) => void |
setNextPage | A callback function that sets pagination to the next page if there is one | () => void |
setPreviousPage | A callback function that sets pagination to the previous page if there is one | () => void |
nextPageDisabled | A boolean to tell if there is a next page available or not | boolean |
prevPageDisabled | A boolean to tell if there is a previous page available or not | boolean |
totalPages | The total number of pages of data | number |
pageSelectValues | A helper variable to be used directly with the <Select values={}> prop | SelectOption[] |
handleSelectChange | A helper variable to be used directly with the <Select onChange={}> prop | SelectProps['onChange'] |
filterValue | A helper variable to be used directly with the TextField value={} prop | string |
handleFilterChange | A helper variable to be used directly with the TextField onChange={} prop | (e: React.ChangeEvent<HTMLInputElement>) => void |
handleSortChange | A callback function to handle sorting | (columnKey: any) => void |
sortValue | The current sort value | SortValueStateType |
handleRowSelected | A callback function to handle selecting a single row | (rowIndex: number / string, isChecked: boolean) => void |
handleAllRowsSelected | A callback function to handle selecting all rows | CheckboxProps['onChange'] |
allRowsSelected | Are all rows selected or not | boolean |
rowsSelected | An array of all the currently selected rows | TableColumnData[] |