universe:react-table

v0.1.3Published 8 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Universe React Table

Fast, flexible, and simple data tables.

This component allows you to display tabular data, and provides sorting, filtering, and pagination over that data.

Table of Contents

Installation

meteor add universe:react-table

Usage

This package needs universe:modules package for importing

The simplest example:

1import {Table} from '{universe:react-table}';
2---
3    <Table className="table" data={[
4        { Name: 'John Vangnner', Age: 18 },
5        { Age: 23,  Name: 'Lee Zalminen' },
6        { Age: 32, Position: 'Developer' },
7    ]} />
8---

While pretty basic, this example demonstrates a couple things:

  • Columns in the data array can be in any order, and you can omit any you like
  • Regular React DOM attributes such as className will pass-through to the rendered <table>
  • Data values can be any type with a toString() method

Clicks

onClickRow

1import {Table} from '{universe:react-table}';
2---
3    <Table onClickRow={(item, i, e) => console.log('clicked on row:', item, i, e);} 
4        className="table"
5        data={[
6            { Name: 'John Vangnner', Age: 18 },
7            { Age: 23,  Name: 'Lee Zalminen' },
8            { Age: 32, Position: 'Developer' },
9    ]} />
10---

Further Customization

You can also manually build up your rows using Tr nested in a table, also using the data prop, but this time containing only one javascript object. This approach can be freely combined with the data property on the <Table>, and is useful if you want to specify per-row attributes such as classes, like so:

1import {Table, Tr} from '{universe:react-table}';
2
3React.renderComponent(
4    <Table className="table" data={[
5        { name: 'Row one', content: 'These are regular data rows' },
6        { name: 'Row two', content: 'They work like above' },
7    ]} >
8        <Tr className="special-row"
9            data={{ name: 'Other Row' , content: 'This is a different row' }} />
10    </Table>,
11    document.getElementById('table')
12);

Even More Customization

If you want to customize the rendering of individual columns, you can go a level deeper by embedding a Td inside your Tr. These have the required column property, and an optional value property if you want to customize the data that's used for sorting and filtering - if the latter isn't specified, the data used will default to the Td's children.

Example:

1import {Table, Tr, Td} from '{universe:react-table}';
2
3---
4    <Table className="table" id="table">
5        <Tr>
6            <Td column="Name" data="John Vangnner">
7                <b>John Vangnner</b>
8            </Td>
9            <Td column="Age">18</Td>
10        </Tr>
11        <Tr>
12            <Td column="Name">Lee Zalminen</Td>
13            <Td column="Age">23</Td>
14        </Tr>
15        <Tr>
16            <Td column="Position">Developer</Td>
17            <Td column="Age">32</Td>
18        </Tr>
19    </Table>
20---

Customizing Columns

To override inferring the column list from the attributes of the passed data objects, you can either:

  • Pass a columns array property to the <Table> component, which can be either:
    • An array of strings, in which case only the given properties will be included as columns in the rendered table.
    • An array of objects, each of which must have a key and label property. The key property is the attribute of the row object from which to retrieve value, and the label is the text to render in the column header row.
  • Define a <Thead> component as the first child of the <Table>, with <Th> components as children (note the exclusion of a <Tr> here), each of which should have a "column" property. The children of these <Th> components (either strings or React components themselves) will be used to render the table headers. For example:
1import {Table, Thead, Th, Tr, Td} from '{universe:react-table}';
2
3---
4    <Table className="table" id="table">
5        <Thead>
6          <Th column="name">
7            <strong className="name-header">First Name, Last Name</strong>
8          </Th>
9          <Th column="age">
10            <em className="age-header">Age, years</em>
11          </Th>
12        </Thead>
13        <Tr>
14            <Td column="name" data="John Vangnner">
15                <b>John Vangnner</b>
16            </Td>
17            <Td column="age">18</Td>
18        </Tr>
19        <Tr>
20            <Td column="name">Lee Zalminen</Td>
21            <Td column="age">23</Td>
22        </Tr>
23        <Tr>
24            <Td column="position">Developer</Td>
25            <Td column="age">32</Td>
26        </Tr>
27    </Table>
28---

In this example, the position column will not be rendered.

Additional node types

Reactable also supports specifying a <tfoot> for your table, via the Tfoot class. Per the HTML spec, there can only be one <Tfoot> per table and its only children should be React.DOM <tr> elements (not <Tr> elements).

Preventing escaping of HTML

If you don't want to go all the way down the JSX rabbit hole to render individual cells as HTML, and you know your source data is safe, you can wrap strings in unsafe to prevent their content from being escaped, like so:

1import {Table, unsafe} from '{universe:react-table}';
2
3---
4    <Table className="table" id="table" data={[
5        {
6            'Name': unsafe('<b>John Vangnner</b>'),
7            'Github': unsafe('<a href="https://github.com/glittershark"><img src="https://d2k1ftgv7pobq7.cloudfront.net/images/services/8cab38550d1f24432facde191031d024/github.png"></a>')
8        },
9        {
10            'Name': unsafe('<b>Jorgen Zhang</b>'),
11            'Github': unsafe('<a href="https://github.com/lofiinterstate"><img src="https://d2k1ftgv7pobq7.cloudfront.net/images/services/8cab38550d1f24432facde191031d024/github.png"></a>')
12        },
13    ]}/>
14---

You can also pass in unsafe strings as column labels or in a <Th>

Pagination

You can also use pagination, by just specifying an itemsPerPage argument to the <Table> component. Include an optional pageButtonLimit argument to customize the number of page buttons in the pagination, which defaults to 10. For example:

1<Table className="table" data={[
2    { Name: 'John Vangnner', Age: '18' },
3    { Age: '23',  Name: 'Lee Zalminen' },
4    { Age: '32', Position: 'Developer' },
5    { Name: 'John Vangnner', Age: '18' },
6    { Age: '44',  Name: 'Test Person' },
7    { Name: 'Another Test', Age: '26', Position: 'Developer' },
8    { Name: 'Third Test', Age: '19', Position: 'Salesperson' },
9    { Age: '23',  Name: 'End of this Page', Position: 'CEO' },
10]} itemsPerPage={4} pageButtonLimit={5} />

Sorting

To enable sorting on all columns, just specify sortable={true} on the <Table> component. For further customization, ie disabling sort or using a custom sort function on a per-column basis, you can pass an array to sortable, which contains either string column names or column objects.

If you need you can pass a callback for event of sorting change by props onSortChange

onSortChange(column, direction)

We've pre-built some sort functions for you.

  • CaseInsensitive will sort strings alphabetically regardless of capitalization (e.g. Joe Vangnner === joe Vangnner)
  • Date will sort dates using JavaScript's native Date parser (e.g. 4/20/2014 12:05 PM)
  • Currency will sort USD format (e.g. $1,000.00)
  • Numeric will parse integer-like strings as integers (e.g. "1")
  • NumericInteger will parse integer strings (use Numeric if you might have floats)

To specify a custom sort function, use the following structure for the column object:

1
2{column: 'Column Name', sortFunction: function(a, b){
3    return a > b ? 1 : -1;
4}}

You can also specify a default sort by passing in either a column name by itself, or an object with a column and a direction paramenter of either asc or desc. If no direction is specified, the default sort will be ascending. Example:

1
2{column: 'Column Name', direction: 'asc' }

Combined example:

1<Table className="table" id="table" data={[
2    { Name: 'Lee Zalminen', Age: '23', Position: 'Programmer'},
3    { Name: 'John Vangnner', Age: '18', Position: 'Engineer'},
4    { Name: 'Jorgen Zhang', Age: '32', Position: 'Developer'}
5]}
6sortable={[
7    {
8        column: 'Name',
9        sortFunction: function(a, b){
10            // Sort by last name
11            var nameA = a.split(' ');
12            var nameB = b.split(' ');
13
14            return nameA[1].localeCompare(nameB[1]);
15        }
16    },
17    'Age',
18    'Position'
19]}
20defaultSort={{column: 'Age', direction: 'desc'}}/>

In case you are constructing your table without the data attribute, and the cells contain some additional HTML elements, you can use the value property on the Td element to define the value to sort for.

In the following example we define two TDs, where the first contains some additional markup. We tell the Td to take "John Vangnner" as value for data handling (filter or sort).

1import {Table, Tdd, Tr} from '{universe:react-table}';
2
3---
4    <Table className="table" id="table" sortable={true}>
5        <Tr>
6            <Td column="Name" value="John Vangnner">
7                <div>
8                   <span>Some Text or Icon</span>
9                   <b>John Vangnner</b>
10                </div>
11            </Td>
12            <Td column="Age">18</Td>
13        </Tr>
14    </Table>
15---

Filtering

You can do simple case-insensitive filtering by specifying a filterable property on the table. This property should contain a list of columns which the filter is performed on. If the filterable property is provided, then an input box with class reactable-filter-input will be prepended to the thead of the table.

Example:

1<Table className="table" id="table" data={[
2    {'State': 'New York', 'Description': 'this is some text', 'Tag': 'new'},
3    {'State': 'New Mexico', 'Description': 'lorem ipsum', 'Tag': 'old'},
4    {'State': 'Colorado',
5     'Description': 'new description that shouldn\'t match filter',
6     'Tag': 'old'},
7    {'State': 'Alaska', 'Description': 'bacon', 'Tag': 'renewed'},
8]} filterable={['State', 'Tag']} />

There is also a filterBy() function on the component itself which takes a single string and applies that as the filtered value. It can be used like so:

1var table = React.renderComponent(
2  <Table className="table" id="table" data={[
3      {'State': 'New York', 'Description': 'this is some text', 'Tag': 'new'},
4      {'State': 'New Mexico', 'Description': 'lorem ipsum', 'Tag': 'old'},
5      {'State': 'Colorado',
6       'Description': 'new description that shouldn\'t match filter',
7       'Tag': 'old'},
8      {'State': 'Alaska', 'Description': 'bacon', 'Tag': 'renewed'},
9  ]} filterable={['State', 'Tag']} />,
10  document.getElementById('table')
11);
12
13table.filterBy('new');

You can also pass in a filterBy prop to control the filtering outside of the Table component:

1var table = React.render(
2  <Table className="table" id="table" data={[
3      {'State': 'New York', 'Description': 'this is some text', 'Tag': 'new'},
4      {'State': 'New Mexico', 'Description': 'lorem ipsum', 'Tag': 'old'},
5      {'State': 'Colorado',
6       'Description': 'new description that shouldn\'t match filter',
7       'Tag': 'old'},
8      {'State': 'Alaska', 'Description': 'bacon', 'Tag': 'renewed'},
9  ]} filterable={['State', 'Tag']}
10  filterBy="new" />,
11  document.getElementById('table')
12);

If you are using your own input field to control the filterBy prop, you can hide the build-in filter input field with the hideFilterInput prop:

1var table = React.render(
2  <Table className="table" id="table" data={[
3      {'State': 'New York', 'Description': 'this is some text', 'Tag': 'new'},
4      {'State': 'New Mexico', 'Description': 'lorem ipsum', 'Tag': 'old'},
5      {'State': 'Colorado',
6       'Description': 'new description that shouldn\'t match filter',
7       'Tag': 'old'},
8      {'State': 'Alaska', 'Description': 'bacon', 'Tag': 'renewed'},
9  ]} filterable={['State', 'Tag']}
10  filterBy="new"
11  hideFilterInput />,
12  document.getElementById('table')
13);

These can be useful if you want to roll your own filtering input field outside of

License

This package is released under the MIT license.

Written based on the wonderful: glittershark/reactable