React Table v6
react-table
is a lightweight, fast and extendable datagrid built for React
v6
This is a v6 of react-table, due to the incredibly massive differences from v7 this branch exists as a way to access its docs and source. I do not intend on offering any long-term support for it. If you intend to keep using v6, I recommend maintaining your own fork of the library and keeping it up to date for your version of React. Otherwise, look into using the most recent version of react-table!
Features
- Lightweight at 11kb (and just 2kb more for styles)
- Fully customizable (JSX, templates, state, styles, callbacks)
- Client-side & Server-side pagination
- Multi-sort
- Filters
- Pivoting & Aggregation
- Minimal design & easily themeable
- Fully controllable via optional props and callbacks
- "Why I wrote React Table and the problems it has solved for Nozzle.io" by Tanner Linsley
CodeSandbox Examples
Versions
React Table v7 is mostly planned and I (@tannerlinsley) am looking for Patreon support to make it a reality. It will require a decent time commitment on my part to not only implement it, but also help people migrate and continue to maintain it. If you would like to contribute to my Patreon goal for v7 and beyond, visit my Patreon and help me out!.
React Table v7 is mostly planned and I (@tannerlinsley) am looking for Patreon support to make it a reality. It will require a decent time commitment on my part to not only implement it, but also help people migrate and maintain it. If you would like to contribute to my Patreon goal for v7, visit my Patreon and help me out!. Gold
Table of Contents
Installation
Note that this installation guide uses the react-table-6
version of the package; while you could access the earier versions of the package by react-table
name, in order to provide a better migration workflow from v6 to the most recent version of the 6.x.x exists as react-table-6
.
- Install React Table as a dependency
$ yarn add react-table-6
$ npm install react-table-6
Usage
- Import the
react-table-6
module
import ReactTable from 'react-table-6'
var ReactTable = require('react-table-6').default
- Import styles by including
react-table.css
import 'react-table-6/react-table.css'
<link rel="stylesheet" href="node_modules/react-table-6/react-table.css">
See the example below for further usage.
CDN
<link
rel="stylesheet"
href="https://unpkg.com/react-table-6@latest/react-table.css"
/>
<script src="https://unpkg.com/react-table-6@latest/react-table.js"></script>
<script src="https://unpkg.com/react-table-6@latest/react-table.min.js"></script>
<script>
var ReactTable = window.ReactTable.default
</script>
Example
import ReactTable from 'react-table-6'
import 'react-table-6/react-table.css'
render() {
const data = [{
name: 'Tanner Linsley',
age: 26,
friend: {
name: 'Jason Maurer',
age: 23,
}
},{
...
}]
const columns = [{
Header: 'Name',
accessor: 'name'
}, {
Header: 'Age',
accessor: 'age',
Cell: props => <span className='number'>{props.value}</span>
}, {
id: 'friendName',
Header: 'Friend Name',
accessor: d => d.friend.name
}, {
Header: props => <span>Friend Age</span>,
accessor: 'friend.age'
}]
return <ReactTable
data={data}
columns={columns}
/>
}
Data
Simply pass the data
prop anything that resembles an array or object. Client-side sorting and pagination are built in, and your table will update gracefully as you change any props. Server-side data is also supported!
<ReactTable
data={[...]}
/>
Pro Tip: Using the resolveData
prop - Any time the data
prop value changes (using a ===
comparison), the table will update, but sometimes you need to materialize, alter, or shape this data before it enters the table. To do this, you can use the resolveData
prop! It receives the data
prop as the only parameter and returns the resolved data.
<ReactTable
data={myData}
resolveData={data => data.map(row => row)}
/>
Props
These are all of the available props (and their default values) for the main <ReactTable />
component.
{
data: [],
resolveData: data => resolvedData,
loading: false,
showPagination: true,
showPaginationTop: false,
showPaginationBottom: true
showPageSizeOptions: true,
pageSizeOptions: [5, 10, 20, 25, 50, 100],
defaultPageSize: 20,
minRows: undefined,
showPageJump: true,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
sortable: true,
multiSort: true,
resizable: true,
filterable: false,
defaultSortDesc: false,
defaultSorted: [],
defaultFiltered: [],
defaultResized: [],
defaultExpanded: {},
defaultFilterMethod: (filter, row, column) => {
const id = filter.pivotId || filter.id
return row[id] !== undefined ? String(row[id]).startsWith(filter.value) : true
},
defaultSortMethod: (a, b, desc) => {
a = a === null || a === undefined ? '' : a
b = b === null || b === undefined ? '' : b
a = typeof a === 'string' ? a.toLowerCase() : a
b = typeof b === 'string' ? b.toLowerCase() : b
if (a > b) {
return 1
}
if (a < b) {
return -1
}
return 0
},
PadRowComponent: () => <span> </span>,
page: undefined,
pageSize: undefined,
sorted: [],
filtered: [],
resized: [],
expanded: {},
onPageChange: undefined,
onPageSizeChange: undefined,
onSortedChange: undefined,
onFilteredChange: undefined,
onResizedChange: undefined,
onExpandedChange: undefined,
pivotBy: undefined,
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
aggregatedKey: '_aggregated',
nestingLevelKey: '_nestingLevel',
originalKey: '_original',
indexKey: '_index',
groupedByPivotKey: '_groupedByPivot',
onFetchData: () => null,
className: '',
style: {},
getProps: () => ({}),
getTableProps: () => ({}),
getTheadGroupProps: () => ({}),
getTheadGroupTrProps: () => ({}),
getTheadGroupThProps: () => ({}),
getTheadProps: () => ({}),
getTheadTrProps: () => ({}),
getTheadThProps: () => ({}),
getTheadFilterProps: () => ({}),
getTheadFilterTrProps: () => ({}),
getTheadFilterThProps: () => ({}),
getTbodyProps: () => ({}),
getTrGroupProps: () => ({}),
getTrProps: () => ({}),
getTdProps: () => ({}),
getTfootProps: () => ({}),
getTfootTrProps: () => ({}),
getTfootTdProps: () => ({}),
getPaginationProps: () => ({}),
getLoadingProps: () => ({}),
getNoDataProps: () => ({}),
getResizerProps: () => ({}),
renderPageJump: ({ onChange, value, onBlur, onKeyPress, inputType, pageJumpText }) => component,
renderCurrentPage: page => component,
renderTotalPagesCount: pages => component,
renderPageSizeOptions: ({
pageSize,
pageSizeOptions,
rowsSelectorText,
onPageSizeChange,
rowsText,
}) => component
column: {
Cell: undefined,
Header: undefined,
Footer: undefined,
Aggregated: undefined,
Pivot: undefined,
PivotValue: undefined,
Expander: undefined,
Filter: undefined,
sortable: undefined,
resizable: undefined,
filterable: undefined,
show: true,
minWidth: 100,
className: '',
style: {},
getProps: () => ({}),
headerClassName: '',
headerStyle: {},
getHeaderProps: () => ({})
footerClassName: '',
footerStyle: {},
getFooterProps: () => ({}),
filterAll: false,
filterMethod: undefined,
sortMethod: undefined,
defaultSortDesc: undefined,
},
expanderDefaults: {
sortable: false,
resizable: false,
filterable: false,
width: 35
},
pivotDefaults: {},
previousText: 'Previous',
nextText: 'Next',
loadingText: 'Loading...',
noDataText: 'No rows found',
pageText: 'Page',
ofText: 'of',
rowsText: 'rows',
pageJumpText: 'jump to page',
rowsSelectorText: 'rows per page',
}
You can easily override the core defaults like so:
import { ReactTableDefaults } from 'react-table-6'
Object.assign(ReactTableDefaults, {
defaultPageSize: 10,
minRows: 3
})
Or just define them as props
<ReactTable
defaultPageSize={10}
minRows={3}
/>
Columns
<ReactTable />
requires a columns
prop, which is an array of objects containing the following properties
[{
Cell: JSX | String | Function
Header: JSX | String | Function
Footer: JSX | String | Function
Filter: JSX | cellInfo => (
<select onChange={event => onFiltersChange(event.target.value)} value={filter ? filter.value : ''}></select>
)
Aggregated: JSX | String | Function
Pivot: JSX | String | Function | cellInfo => (
<span>
<Expander /><PivotValue /> // By default, will utilize the the PivotValue and Expander components at run time
</span>
),
PivotValue: JSX | String | Function
Expander: JSX | String | Function
accessor: 'propertyName',
id: 'myProperty',
sortable: boolean,
resizable: boolean,
filterable: boolean,
show: true,
width: undefined,
minWidth: 100,
maxWidth: undefined,
pivot: false,
expander: false,
className: '',
style: {},
headerClassName: '',
headerStyle: {},
getHeaderProps: (state, rowInfo, column, instance) => ({}),
columns: [...],
footerClassName: '',
footerStyle: {},
getFooterProps: (state, rowInfo, column, instance) => ({}),
filterMethod: (filter, row || rows, column) => {return true},
filterAll: false
}]
Renderers
React Table supports very flexible renderers for just about everything:
Cell
- Renders a standard cellHeader
- Renders a column header or column group headerFooter
- Renders a column footerFilter
- Renders a column's filter UIAggregated
- Renders an aggregated cellPivot
- Renders a pivoted cell (by default, will utilize Expander
and PivotValue
renderers)PivotValue
- Renders the value inside a Pivot
rendererExpander
- Renders the Expander used in both the default Pivot
renderer and any expander-designated column
Any of these renderers can be one of the following:
- A React Class
- JSX or any rendered react component
- Stateless functional component
- Function that returns any primitive
All of these formats receive the following props:
{
row: Object,
original: ,
index: '',
viewIndex: '',
level: '',
nestingPath: '',
aggregated: '',
groupedByPivot: '',
subRows: '',
isExpanded: '',
value: '',
resized: '',
show: '',
width: '',
maxWidth: '',
tdProps: '',
columnProps: '',
classes: '',
styles: ''
}
Accessors
Accessors are functions that return the value to populate the row's value for the column.
This lets the render function not have to worry about accessing the correct data, the value is automatically populated in it's props.
If a string
or array
is passed the default accessor is used.
The default accessor will parse the input into an array and recursively flatten it.
Any values that contain a dot (.
) will be split.
Any values that contain bracket ([]
) will be split.
This array is then used as the path to the value to return.
("$" is the placeholder value that would be returned by the default accessor)
value | path | data |
---|
"a" | ["a"] | {"a": $} |
"a.b" | ["a", "b"] | {"a": {"b": $}} |
"a[0]" | ["a", "0"] | {"a": [$]} |
["a.b", "c"] | ["a", "b", "c"] | {"a": {"b": {"c": $}}} |
NOTE
If your data has a field/key with a dot (.
) you will need to supply a custom accessor.
Column Header Groups
To group columns with another header column, just nest your columns in a header column. Header columns utilize the same header properties as regular columns.
const columns = [{
Header: 'Favorites',
headerClassName: 'my-favorites-column-header-group'
columns: [{
Header: 'Color',
accessor: 'favorites.color'
}, {
Header: 'Food',
accessor: 'favorites.food'
}, {
Header: 'Actor',
accessor: 'favorites.actor'
}]
}]
Custom Cell, Header and Footer Rendering
You can use any react component or JSX to display content in column headers, cells and footers. Any component you use will be passed the following props (if available):
row
- Original row from your dataoriginal
- The post-accessed values from the original rowindex
- The index of the rowviewIndex
- the index of the row relative to the current pagelevel
- The nesting depth (zero-indexed)nestingPath
- The nesting path of the rowaggregated
- A boolean stating if the row is an aggregation rowsubRows
- An array of any expandable sub-rows contained in this row
const columns = [
{
Header: () => (
<span>
<i className="fa-tasks" /> Progress
</span>
),
accessor: 'progress',
Cell: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor:
row.value > 66
? '#85cc00'
: row.value > 33
? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}
]
Styles
- React-table ships with a minimal and clean stylesheet to get you on your feet quickly.
- The stylesheet is located at
react-table-6/react-table.css
. - There are countless ways to import a stylesheet. If you have questions on how to do so, consult the documentation of your build system.
Classes
- Adding a
-striped
className to ReactTable will slightly color odd numbered rows for legibility - Adding a
-highlight
className to ReactTable will highlight any row as you hover over it
CSS
We think the default styles looks great! But, if you prefer a more custom look, all of the included styles are easily overridable. Every single component contains a unique class that makes it super easy to customize. Just go for it!
JS Styles
Every single react-table element and get[ComponentName]Props
callback supports classname
and style
props.
Custom Props
Built-in Components
Every single built-in component's props can be dynamically extended using any one of these prop-callbacks:
<ReactTable
getProps={fn}
getTableProps={fn}
getTheadGroupProps={fn}
getTheadGroupTrProps={fn}
getTheadGroupThProps={fn}
getTheadProps={fn}
getTheadTrProps={fn}
getTheadThProps={fn}
getTheadFilterProps={fn}
getTheadFilterTrProps={fn}
getTheadFilterThProps={fn}
getTbodyProps={fn}
getTrGroupProps={fn}
getTrProps={fn}
getTdProps={fn}
getPaginationProps={fn}
getLoadingProps={fn}
getNoDataProps={fn}
getResizerProps={fn}
/>
If used, a callback prop must return a valid object, even if it's an empty one.
These callbacks are executed with each render of the element with four parameters:
- Table State
- RowInfo (undefined if not applicable)
- Column (undefined if not applicable)
- React Table Instance
This makes it extremely easy to add, say... a row click callback!
<ReactTable
getTdProps={(state, rowInfo, column, instance) => {
return {
onClick: (e, handleOriginal) => {
console.log('A Td Element was clicked!')
console.log('it produced this event:', e)
console.log('It was in this column:', column)
console.log('It was in this row:', rowInfo)
console.log('It was in this table instance:', instance)
if (handleOriginal) {
handleOriginal()
}
}
}
}}
/>
You can use these callbacks for dynamic styling as well!
<ReactTable
getTrProps={(state, rowInfo, column) => {
return {
style: {
background: rowInfo.row.age > 20 ? 'green' : 'red'
}
}
}}
/>
Column Components
Just as core components can have dynamic props, columns and column headers can too!
You can utilize either of these prop callbacks on columns:
const columns = [{
getHeaderProps: () => (...),
getProps: () => (...)
}]
In a similar fashion these can be used to dynamically style just about anything!
const columns = [
{
getProps: (state, rowInfo, column) => {
return {
style: {
background: rowInfo.row.name === 'Santa Clause' ? 'red' : null
}
}
}
}
]
Pivoting and Aggregation
Pivoting the table will group records together based on their accessed values and allow the rows in that group to be expanded underneath it.
To pivot, pass an array of columnID
's to pivotBy
. Remember, a column's id
is either the one that you assign it (when using a custom accessors) or its accessor
string.
<ReactTable
...
pivotBy={['lastName', 'age']}
/>
Naturally when grouping rows together, you may want to aggregate the rows inside it into the grouped column. No aggregation is done by default, however, it is very simple to aggregate any pivoted columns:
const columns = [
{
Header: 'Age',
accessor: 'age',
aggregate: (values, rows) => _.round(_.mean(values)),
Aggregated: row => {
return <span>row.value (avg)</span>
}
},
{
Header: 'Visits',
accessor: 'visits',
aggregate: (values, rows) => _.sum(values)
}
]
Pivoted columns can be sorted just like regular columns including holding down the <shift>
button to multi-sort.
Sub Tables and Sub Components
By adding a SubComponent
props, you can easily add an expansion level to all root-level rows:
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={row => {
return (
<div>
You can put any component you want here, even another React Table! You
even have access to the row-level data if you need! Spark-charts,
drill-throughs, infographics... the possibilities are endless!
</div>
)
}}
/>
Server-side Data
If you want to handle pagination, sorting, and filtering on the server, react-table
makes it easy on you.
- Feed React Table
data
from somewhere dynamic. eg. state
, a redux store, etc... - Add
manual
as a prop. This informs React Table that you'll be handling sorting and pagination server-side - Subscribe to the
onFetchData
prop. This function is called at componentDidMount
and any time sorting, pagination or filterting is changed in the table - In the
onFetchData
callback, request your data using the provided information in the params of the function (current state and instance) - Update your data with the rows to be displayed
- Optionally set how many pages there are total
<ReactTable
...
data={this.state.data}
pages={this.state.pages}
loading={this.state.loading}
manual
onFetchData={(state, instance) => {
this.setState({loading: true})
Axios.post('mysite.com/data', {
page: state.page,
pageSize: state.pageSize,
sorted: state.sorted,
filtered: state.filtered
})
.then((res) => {
this.setState({
data: res.data.rows,
pages: res.data.pages,
loading: false
})
})
}}
/>
For a detailed example, take a peek at our async table mockup
Fully Controlled Component
React Table by default works fantastically out of the box, but you can achieve even more control and customization if you choose to maintain the state yourself. It is very easy to do, even if you only want to manage parts of the state.
Here are the props and their corresponding callbacks that control the state of the a table:
<ReactTable
page={0}
pageSize={20}
sorted={[{
id: 'lastName',
desc: true
}, {
id: 'firstName',
desc: true
}]}
expanded={{
1: true,
4: true,
5: {
2: true,
3: true
}
}}
filtered={[{
id: 'lastName',
value: 'linsley'
}]}
resized={[{
"id": "lastName",
"value": 446.25
}]}
onPageChange={(pageIndex) => {...}}
onPageSizeChange={(pageSize, pageIndex) => {...}}
onSortedChange={(newSorted, column, shiftKey) => {...}}
onExpandedChange={(newExpanded, index, event) => {...}}
onFilteredChange={(filtered, column) => {...}}
onResizedChange={(newResized, event) => {...}}
/>
Functional Rendering
Possibly one of the coolest features of React-Table is its ability to expose internal components and state for custom render logic. The easiest way to do this is to pass a function as the child of <ReactTable />
.
The function you pass will be called with the following items:
- Fully-resolved state of the table
- A function that returns the standard table component
- The instance of the component
You can then return any JSX or react you want! This turns out to be perfect for:
- Accessing the internal state of the table without a
ref
- Decorating the table or extending it with your own UI
- Building your own custom display logic
Accessing internal state and wrapping with more UI:
<ReactTable data={data} columns={columns}>
{(state, makeTable, instance) => {
return (
<div
style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}
>
<pre>
<code>
state.allVisibleColumns ==={' '}
{JSON.stringify(state.allVisibleColumns, null, 4)}
</code>
</pre>
{makeTable()}
</div>
)
}}
</ReactTable>
The possibilities are endless!
Sorting
Sorting comes built in with React-Table.
- Click a column header to sort by its accessor.
- Click it again to reverse the sort.
- Set
defaultSortDesc
property to true
to make the first sort direction default to descending. - Override a specific column's default sort direction by using the same
defaultSortDesc
property on a column, set to true
Multi-Sort
When clicking on a column header, hold shift to multi-sort! You can toggle ascending
descending
and none
for multi-sort columns. Clicking on a header without holding shift will clear the multi-sort and replace it with the single sort of that column. It's quite handy!
You can set the multiSort
prop to false
to disable this feature (which may be useful for server-side sorting when you are not
going to sort multiple columns).
Custom Sorting Algorithm
To override the default sorting algorithm for the whole table use the defaultSortMethod
prop.
To override the sorting algorithm for a single column, use the sortMethod
column property.
Supply a function that implements the native javascript Array.sort
interface. This is React Table's default sorting algorithm:
a
the first value to compareb
the second value to comparedesc
true if sort is descending, false if ascending
defaultSortMethod = (a, b, desc) => {
a = a === null || a === undefined ? -Infinity : a
b = b === null || b === undefined ? -Infinity : b
a = typeof a === 'string' ? a.toLowerCase() : a
b = typeof b === 'string' ? b.toLowerCase() : b
if (a > b) {
return 1
}
if (a < b) {
return -1
}
return 0
}
Filtering
Filtering can be enabled by setting the filterable
option on the table.
If you don't want particular column to be filtered you can set the filterable={false}
option on the column.
By default the table tries to filter by checking if the row's value starts with the filter text. The default method for filtering the table can be set with the table's defaultFilterMethod
option.
If you want to override a particular column's filtering method, you can set the filterMethod
option on a column.
By default, filterMethod
is passed a single row of data at a time, and you are responsible for returning true
or false
, indicating whether it should be shown.
Alternatively, you can set filterAll
to true
, and filterMethod
will be passed the entire array of rows to be filtered, and you will then be responsible for returning the new filtered array. This is extremely handy when you need to utilize a utility like fuzzy matching that requires the entire array of items.
To completely override the filter that is shown, you can set the Filter
column option. Using this option you can specify the JSX that is shown. The option is passed an onChange
method which must be called with the the value that you want to pass to the filterMethod
option whenever the filter has changed.
See Custom Filtering demo for examples.
Component Overrides
Though we confidently stand by the markup and architecture behind it, react-table
does offer the ability to change the core componentry it uses to render everything. You can extend or override these internal components by passing a react component to it's corresponding prop on either the global props or on a one-off basis like so:
import { ReactTableDefaults } from 'react-table-6'
Object.assign(ReactTableDefaults, {
TableComponent: component,
TheadComponent: component,
TbodyComponent: component,
TrGroupComponent: component,
TrComponent: component,
ThComponent: component,
TdComponent: component,
TfootComponent: component,
ExpanderComponent: component,
AggregatedComponent: component,
PivotValueComponent: component,
PivotComponent: component,
FilterComponent: component,
PaginationComponent: component,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: component,
NoDataComponent: component,
ResizerComponent: component
})
<ReactTable
TableComponent={Component},
TheadComponent={Component},
/>
If you choose to change the core components React-Table uses to render, you must make sure your replacement components consume and utilize all of the supplied and inherited props that are needed for that component to function properly. We would suggest investigating the source for the component you wish to replace.
HOC Extensions
This section is about expanding ReactTable using Higher Order Components/Functions.
Covered in this section
- A Brief explanation of HOCs and why they are a good approach for ReactTable enhancements
- Documentation of the currently available HOCs
- TreeTable
- SelectTable
- Documentation of the standard for writing HOCs with ReactTable
What are HOCs and why use them with ReactTable
HOCs (or Higher Order Components/Functions) are either a React Component (or a function that returns a React Component)
that are used to enhance the functionality of an existing component. How much you can enhance depends on the props that
the component exposes.
Fortunately, ReactTable exposes a LOT of functionality as props to the component. In some cases there are too many
props to keep track of and that is where HOCs come in.
You can write a HOC that just focusses on the additional functionality you want to enhance and keep those enhancements to
reuse over and over again when you need them. You don't have to edit the ReactTable source code, just wrap ReactTable in one or
more HOCs (more on some issues related to chaining HOCs later) that provide the additional functionality you want to expose.
The most obvious HOC is one that can add checkbox
or select functionality. The HOC included provides select
functionality
that allows the developer to specify if they want a checkbox
or radio
style of select column. The implementation of the
selection is recorded (e.g. in component state, Redux, etc.) and how to manage multiple selections. The HOC really only handles
the rendering pieces.
But there is more documentation on the select
HOC below.
Currently Available HOCs
Any of the below HOCs can be imported from react-table like so:
import ReactTable from "react-table-6";
import treeTableHOC from "react-table-6/lib/hoc/treeTable";
const TreeTable = treeTableHOC(ReactTable);
Swap treeTable
and TreeTable
with any of the other HOC names as necessary.
TreeTable
TreeTable takes over the rendering of the generated pivot rows of ReactTable so that they appear more like an expandable Tree.
It accomplishes this by rendering a 100% wide div and then only rendering the cell that controls the pivot at that level.
Using it is as simple as doing the following:
const TreeTable = treeTableHOC(ReactTable);
After you have done the above, you can then use TreeTable
just as you would ReactTable
but it will render pivots using
the Tree style described above.
SelectTable
SelectTable is a little trickier. The HOCs attempt to avoid adding additional state and, as there is no internal ID for a row that
can be relied on to be static (ReactTable just reuses indexes when rendering) the developer has to maintain the state outside of even
the wrapped component. So it is largely based on callbacks.
You include the HOC in the same manner as you would for the treeTableHOC but then need to provide the following overrides:
- isSelected - returns
true
if the key passed is selected otherwise it should return false
- selectAll - a property that indicates if the selectAll is set (
true|false
) - toggleAll - called when the user clicks the
selectAll
checkbox/radio - toggleSelection - called when the use clicks a specific checkbox/radio in a row
- selectType - either
checkbox|radio
to indicate what type of selection is required
Note: The select field defaults to the accessor _id
property in order to render the select field for that particular row. If your objects have different
unique ID fields, make sure to tell React Table that by passing it the keyField
property.
<ReactTable keyField="id" />
In the case of radio
there is no selectAll
displayed but the developer is responsible for only making one selection in
the controlling component's state. You could select multiple but it wouldn't make sense and you should use checkbox
instead.
You also have to decide what selectAll
means. Given ReactTable is a paged solution there are other records off-page. When someone
selects the selectAll
checkbox, should it mark every possible record, only what might be visible to due a Filter or only those items
on the current page?
The example opts for the middle approach so it gets a ref
to the ReactTable instance and pulls the sortedData
out of the resolved
state (then walks through those records and pulls their ID into the selection
state of the controlling component).
You can also replace the input component that is used to render the select box and select all box:
- SelectAllInputComponent - the checkbox in the top left corner
- SelectInputComponent - the checkbox used on a row
SelectTreeTable
SelectTreeTable is a combination of TreeTable and SelectTable.
To function correctly the chain has to be in the correct order as follows (see the comments in the guid on HOCs below).
const SelectTreeTable = selectTableHOC(treeTableHOC(ReactTable));
In this particular instance it is (probably) because the functions need access to the state on the wrapped component to manage
the selected items. Although that is not totally clearly the issue.
FoldableTable
FoldableTable is a HOC that make the columns are foldable. The reason I developed this HOC because when working on the real project related to the financial which display so many columns for validation and comparison.
So foldable columns allow users to temporary hidden the unwanted to columns so that they can focus on the data that they want to see.
How it works
const FoldableTable = FoldableTableHOC(ReactTable);
It will scan all the columns which foldable
is true
and apply the foldable column feature. This feature will work for both normal columns and header columns as samples below.
render(){
return <FoldableTable
columns={[{
Header: "Name",
foldable: true,
columns: [{
Header: "First Name",
accessor: "first_name"
},{
Header: "Last Name",
accessor: "last_name"
}]
},{
Header: "Info",
foldable: true,
columns: [{
Header: "Email",
accessor: "email"
},{
Header: "Gender",
accessor: "gender"
}]
}]
}/>
}

render() {
return <FoldableTable
columns={[{
Header: "First Name",
accessor: "first_name"
},
{
Header: "Last Name",
accessor: "last_name",
foldable: true,
},
{
Header: "Email",
accessor: "email",
foldable: true,
},
{
Header: "Gender",
accessor: "gender",
foldable: true,
}]}></FoldableTable>
}

- The
FoldableTable
also fully compatible with existing HOCs, below is with selectTableHOC.

State management
If you would like to manage the state of FoldableTable, then add the following codes.
render() {
return <FoldableTable
onFoldChange={newFolded => this.setState(p => { return { folded: newFolded } })}
folded={this.state.folded}
/>
}
Custom Components
- FoldIconComponent: to render the Icon of buttons.
- FoldButtonComponent: to render the folding buttons for each Column.
With default rendering as below.
const defaultFoldIconComponent = ({ collapsed }) => {
};
const defaultFoldButtonComponent = ({ header, collapsed, icon, onClick }) => {
};
AdvancedExpandTable
HOC which allows any Cell in the row to toggle the row's
SubComponent (expand/collapse). Also allows the SubComponent to toggle itself. Technically supports toggling any row's SubComponent.
These are the expand functions available to any SubComponent or Column Cell:
toggleRowSubComponent
showRowSubComponent
hideRowSubComponent
They are available through the props.columnProps.rest
object.
On any change to the props, the table will reset the expanded state.
Accepts a onExpandedChange callback to be called whenever the table expanded state changes
Note: only supports 1 level of nesting.
Example usage in a Column Cell Renderer:
Cell: props => {
const {
value
columnProps: { rest: { showRowSubComponent } },
nestingPath
} = props;
return (
<div>
<button
onClick={e => showRowSubComponent(nestingPath, e)}
>
{value}
</button>
</div>
);
}
Example usage in the ReactTable SubComponent (toggle itself):
const AdvancedExpandReactTable = advancedExpandTableHOC(ReactTable);
<AdvancedExpandReactTable>
...
SubComponent={({ row, nestingPath, toggleRowSubComponent }) => {
return (
<div>
<button
onClick={e => toggleRowSubComponent({ nestingPath }, e)}
>
{row.value}
</button>
</div>
);
}}
/>
Each Column Renderer (E.g. Cell ) gets the expand functions in its props and each SubComponent gets the expand functions in its props
Expand functions takes the nestingPath
or rowInfo
given to each
Column Renderer and SubComponent already by ReactTable.
HOC Guide for ReactTable
There are a few rules required when writing a HOC for ReactTable (other than meeting the normal lint standards - which are
still being developed).
Firstly, there are issues with ref
when you write a HOC. Consider a deeply nested component wrapped in multiple HOCs...
A HOC in the middle of the chain requires access to the instance of the component it thinks it is wrapping but there is at
least one other wrapper in the way. The challenge is: How do I get to the actual wrapped component?
Each HOC is required to be a React Class so that a ref
can be obtained against each component:
<Component ... ref={r => this.wrappedInstance = r} />
NOTE: "Component" can also be the <ReactTable />
instance.
Then the following method needs
to be placed on the class so that it exposes the correct instance of ReactTable:
getWrappedInstance() {
if (!this.wrappedInstance) console.warn('<component name here> - No wrapped instance')
if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance()
else return this.wrappedInstance
}
Essentially this will walk down the chain (if there are chained HOCs) and stop when it gets to the end and return the wrapped instance.
Finally, sometimes the chains need to be in a specific order to function correctly. It is not clear if this is just an architectural
issue or if it would be better solved using a library like recompose
. Anyone who is able to contribute a reliable solution to this
is welcome to submit a PR.
Contributing
To suggest a feature, create an issue if it does not already exist.
If you would like to help develop a suggested feature follow these steps:
- Fork this repo
- Install dependencies with
$ yarn
- Auto-build files as you edit with
$ yarn run watch
- Implement your changes to files in the
src/
directory - Run the React Story locally with
$ yarn run docs
- View changes as you edit
docs/src
- Submit PR for review
Scripts
$ yarn run watch
Watches files and builds via babel$ yarn run docs
Runs the storybook server$ yarn run test
Runs the test suite
Used By