React Collapsing Table

Paul Darragh
6 min readDec 21, 2017

--

When evaluating the react table ecosystem we found that every open source table we looked at was missing a feature or two that we wanted so we decided to build and share our table with everyone! This table has the following features.

  • Expandable Row that makes the table mobile friendly
  • Prioritization of which columns remain shown as columns and which collapse into expanded rows
  • Search built in with highlighting of content
  • Creating your own custom react components
  • Custom functions that can be called by your custom component

As a front end engineer I love tackling new problems and making a user’s life a little bit easier each day. One of the front end developers on my team was talking about how she loves the datatables.net because of how mobile friendly the table is. The reason we aren’t using it is due to our team using React and datatables is a jQuery library. With React and jQuery possibly not playing well with each other we decided it would be a good time to take on a new challenge while adding a few more bells and whistles.

During this rewrite of the datatable we decided that we wanted to be able to determine the order in which each column was displayed, in what order would we hide columns and how can we make it easy for other projects to use this table and pass it their own components and pass those components a way to trigger an action defined outside of this table.

We set up the table so that you pass it a few basic props:

  • columns: a list of the columns you want the table to display
  • rows: a list of objects that contain all of the data

Here is an example of a column and row

rows = [
{ id: 1, firstName: 'Paul', lastName: 'Darragh', }
]
columns = [
{ accessor: 'firstName', label: 'First Name', priorityLevel: 1, position: 1, minWidth: 150, },
{ accessor: 'lastName', label: 'Last Name', priorityLevel: 2, position: 2, minWidth: 150, },
]
  • The accessor in the column tells it how to find the data it needs for a specific cell in each row.
  • The label tells it what to name the column
  • The priorityLevel tells the row in what order should I hide these rows
  • The position tells the table where do you want me to place the column on the table
  • The most important is the minWidth which the table uses to determine how many rows can be on the screen at once and when do should I hide or show a row?

This will get you started and if you decide that your fancy react/redux project needs to be able to display something else there or kick off a redux action you can write your own custom component to change how the cell is displayed and pass in a function that the cell can call when something occurs.

So let’s add a picture that can be displayed in each row.

A Picture was added!
import TablePhoto from './components/TablePhoto';rows = [
{ id: 1, firstName: 'Paul, lastName: 'Darragh', photoUrl: 'https://s3.amazonaws.com/react-collapsing-table-photos/5.jpeg' }
]
columns = [
{ accessor: 'firstName', label: 'First Name', priorityLevel: 1, position: 1, minWidth: 150, },
{ accessor: 'lastName', label: 'Last Name', priorityLevel: 2, position: 2, minWidth: 150, },
{ accessor: 'photoUrl', label: 'Photo', priorityLevel: 3, position: 3, minWidth: 200, CustomComponent: TablePhoto },
]

This CustomComponent now points to a file I made that receives all of the information for a single row and what column the row is in (the accessor). Using this information I can grab the image url by simply saying row[accessor]

import React from 'react';

const TablePhoto = ({ row, accessor }) => {
return <span style={{height: 200, width: 200, backgroundColor: 'grey'}}>
<img src={ row[accessor] } className="img-fluid" width="200" height="200" alt=''/>
</span>
};

export default TablePhoto;

Now our table will display an image in the third column. But we want to be able to hook it up to a modal that we made to display a larger image of the component when the image is clicked.

Let’s change the TablePhoto component to add a onClick function to the image.

Expanding Modal On Picture Click
import React from 'react';

const TablePhoto = ({ row, accessor, CustomFunction }) => {
const clicked = () => CustomFunction({ imageURL: row[accessor] });
return <span style={{height: 200, width: 200, backgroundColor: 'grey'}}>
<img onClick={ clicked } src={ row[accessor] } className="img-fluid" width="200" height="200" alt=''/>
</span>
};

export default TablePhoto;

What we needed to change to the TablePhoto component was to add CustomFunction as a prop that we can use to create a onClick function that when clicked will send back the image url to the function that the CustomFunction is calling.

But now how do we pass the table this custom function? It is pretty easy actually. The table takes a prop called callbacks that we pass in as an object with the key being the column accessor and the value being the function we want to call, like this.

imports all the things

export class ReceiptsScreen extends Component {
clickedImage = ({ imageURL }) => {
this.props.actions.clickedImage({ imageURL });
}

render() {
const { rows, columns, } = this.props;
const callbacks = { photoUrl: this.clickedImage }
return (
<ReactCollapsingTable
rows={ rows }
columns={ columns }
callbacks={ callbacks } />
);
}
}

setups up all of the redux things

Now we can click the photo and have a picture pop up!

That is a simple intro into using this table! You can view it on github and if you want to see the actual implementation of this example you can click here to see the working example and here to see the working example code.

This is the first open source software contribution I have ever done so it was a journey learning from the first attempt at making this table using redux, which we discovered wouldn’t be a friendly option for other developers to use. So we scaled it back to just react and invested some time in leveling up our npm publishing skills. I want to give a shout out to Noel Broda for his article on how to make a basic react component that publishes to npm, which provided a solid place to start when publishing this table.

We are excited to see what other people build with this and what new features people think of! We are also proud to say as we add more features we will continue to provide 100% test coverage for this component.

I would like to note that this has been built for react only without react native or any other library support in mind and that it has only been tested with react 15 and 16. While we expect this to work for almost every use case this table has not been optimized to handle infinite scrolling or large datasets over a thousand records.

--

--

Paul Darragh

A Full Stack Developer working as a Front End Engineer at Massmutual