1.3.0 • Published 4 years ago

react-infinite-table v1.3.0

Weekly downloads
125
License
MIT
Repository
github
Last release
4 years ago

React Infinite Table

NPM version NPM license npm bundle size npm bundle size NPM total downloads NPM monthly downloads

A browser-ready efficient scrolling table with fixed header and footer, and much more!

Check out the demo

Features

  • ✅ Render only the visibile rows
  • ✅ Fixed header
  • ✅ Fixed footer
  • ✅ Fixed left column(s)
  • ✅ Column resize
  • ✅ Column order changes (by dragging)
  • ✅ Row selection (handling shift/modifier during click)
  • ✅ Multiple rows selection
    • ⌘/Ctrl + Click: toggle selection
    • ⇧ + Click: select all the rows between the previously clicked row and the currently clicked row.
  • 🔜 Rows with different heights / free height
  • 🎉 Uses the HTML <table> standard tags!
  • 🎉 No use of javascript to sync scroll between fixed columns/rows!

Getting started

Install react-infinite-table using npm.

npm install react-infinite-table --save

Import and use as follows:

import {Table} from 'react-infinite-table';

const rows = [
  { /* the row's data */ }, 
  //...
]

const columns = [
  { 
    cellRenderer: ({ columnIndex, column, rowData, rowIndex, className }) => {
      return (
        <td className={className}>
          {rowData.xxx}
        </td>
      )
    },
    headerRenderer: ({ columnIndex, column, className }) => {
      return (
        <th className={className}>
          {column.name}
        </th>
      )
    },
    footerRenderer: ({ columnIndex, column, className }) => {
      return (
        <td className={className}>
          {column.xxx}
        </td>
      )
    },
    width: 90,
    name: '...'
  },
  //...
]

<Table
  className='example-table'
  tableClassName='table table-bordered table-striped' // example using bootstrap
  height={200}
  rowHeight={30}
  rows={rows}
  columns={columns}
  headerCount={1}
  footerCount={1}
  fillTableWidth={true|false}
  rowIdKey='id'
  noRowsRenderer={() => 'No rows'}
  // keep the first column fixed:
  fixedColumnsCount={1}
  // row selection
  selectedRows={this.state.selectedRows}
  onSelectionChange={selectedRows => { this.setState({selectedRows}) }}
  canSelectMultipleRows={true|false}
  // infinite load:
  infiniteLoadBeginEdgeOffset={150}
  isInfiniteLoading={true|false}
  onInfiniteLoad={() => { /* fetch your data ... */ }}
  getLoadingSpinner={() => <div>Loading...</div>}
  // display from bottom upwards, like a Chat or Message Box 
  displayBottomUpwards={displayBottomUpwards}
  // allows column resize
  onColumnWidthChange={(columnIndex, width) => { /* update columns... */ }}
  // allows column reorder (by dragging)
  onColumnOrderChange={(fromIndex, toIndex) => { /* update columns... */ }}
/>

Similar packages

This package has been inspired by some existing library dealing with tables in react.

The initial code started from a "fork" of the react-infinite package, that implements a scrollable container with a lot of items by rendering only DOM nodes that the user is able to see (or might soon see).

The definition of the columns and the rendering of the cells is inspired by react-virtualized.

CSS is used to fix header, footer and some columns, using position: sticky. This has been inspired by ember-table.

Comparison of similar packages:

Featurereact-infinite-tablereact-virtualizedreact-base-table
HTML <table> standard tags
Fixed columns
Fixed header
Fixed footer
Column resize (by dragging)
Column reorder (by dragging)
Row selection
No use of javascript to sync scroll between fixed columns/rows
Sizenpm bundle size npm bundle sizenpm bundle size npm bundle sizenpm bundle size npm bundle size

Dependencies

react-infinite-table has very few dependencies that are managed by npm.

The following peer dependencies must be specified by your project in order to avoid version conflicts: react, react-dom. NPM will not automatically install these for you but it will show you a warning message with instructions on how to install them.

Documentation

Table Prop Types

Table is the main component and it's responsible of rendering your table.

PropertyTypeRequired?Description
heightNumberThe height of the table. If you want the table to take the height of the container, you should have a look at the AutoSizer component
overscanSizeNumberHow much you want to render above/below the visible bounds of the table (in pixels). Default: overscanSize: 500
rowHeightNumberA fixed row height (TODO: planning to allow undefined, and each row will auto size to fit content!)
rowsArrayAn array of data, one object for each row. There are no required keys, but if you want to use the "row selection" feature, an unique "row id" will be needed.
columnsColumnOne or more columns describing the data displayed in this table
headerCountNumberNumber of header rows in the <thead> section of the table. Default: headerCount: 1
footerCountNumberNumber of footer rows in the <tfoot> section of the table. Default: footerCount: 0
fixedColumnsCountNumberNumber of columns to keep fixed on the left of the table while scrolling horizontally. Default: fixedColumnsCount: 0
fillTableWidthBooleanIf fillTableWidth = true and the combined width of the columns is less than the table's width, the columns will grow in order to fill the table. Default: fillTableWidth: false
noRowsRendererFunctionCallback used to render placeholder content when the number of rows is 0. Default: noRowsRenderer: undefined - the table will be empty.
rowIdKeyStringThe key used to extract the id of a row from the row's data object. If present, it is used as a key for the table's row, otherwise the rowIndex is used. Needed if row selection is enabled.
selectedRowsObjectAn object with the selected rows' ids as key, and true as value. Example: { 1: true, 2: true, 5: true } - the rows with ids 1, 2 and 5 will be selected. Default: selectedRows: undefined - no selected rows.
canSelectMultipleRowsBooleanWhether or not multiple rows can be selected. If true, using ⌘/Ctrl + Click on a row, the row will be selected/deselected, and using ⇧ + Click will select all the rows between the previously selected row and the clicked row. Default: canSelectMultipleRows: false
onSelectionChangeFunctionThe callback to call when the selection changes. For example, use (selectionRows) => { this.setState({ selectionRows }) } to update your state to reflect the new selection. Default: onSelectionChange: undefined - Row selection is not allowed.
infiniteLoadBeginEdgeOffsetNumberHow far from the bottom of the table we call the onInfiniteLoad function to fetch the new data. Default: infiniteLoadBeginEdgeOffset: undefined - Infinite load is not enabled.
onInfiniteLoadFunctionThe callback used to start a fetch operation to get new rows. You should use this callback to start the async loading of new data and then update the rows props with the new rows. Default: () => {}
getLoadingSpinnerFunctionCallback used to render a loading message/spinner during data loading. Default: () => <div />
isInfiniteLoadingBooleanSet to true if you want the show the loading spinner. Default: isInfiniteLoading: undefined
displayBottomUpwardsBooleanWhether or not to show the rows starting at the bottom, like in a chat/messaging application. Default: displayBottomUpwards: false
classNameStringA class to add to the table container <div>. Default: className: undefined
tableClassNameStringA class to add to the <table> node. Default: tableClassName: undefined
styleObjectPassthrough prop to the table container <div>. Default: style: undefined
onColumnWidthChangeFunctionCallback called when a column's width has changed. You should update the Column definition accordingly. (columnIndex, width) => { /* update columns... */ }. Default: onColumnWidthChange: undefined - Column's can't be resized.
onColumnOrderChangeFunctionCallback called when a column order position is changed from fromIndex to toIndex. You should update the Columns array accordingly. (fromIndex, toIndex) => { /* update columns... */ }. Default: onColumnOrderChange: undefined - Column's can't be reordered. You can use the helper function reorderColumns. Learn more

Column Prop Types

PropertyTypeRequired?Description
widthNumberThe width of the column in pixels.
cellRendererFunctionCallback responsible for rendering a cell's contents. Learn more
headerRendererFunctionOptional callback responsible for rendering a column's header column. Learn more
footerRendererFunctionOptional callback responsible for rendering a column's footer column. Learn more

cellRenderer

Callback responsible for rendering a cell's contents. It should implement the following signature:

({
  className: string,
  columnIndex: number,
  column: object,
  rowIndex: number,
  rowData: object
}) => {
  return <td className={className}>{/*...*/}</td>
}

You should return a <td> node (or a Component that renders a td) since this node will be rendered in the tbody > tr section of the table. You should always pass the className prop.

headerRenderer

Callback responsible for rendering a cell's header column. It should implement the following signature:

({
  className: string,
  columnIndex: number,
  column: object
}) => {
  return <th className={className}>{/*...*/}</th>
}

You should return a <th> node (or a Component that renders a th) since this node will be rendered in the thead > tr section of the table. You should always pass the className prop.

footerRenderer

Callback responsible for rendering a cell's footer column. It should implement the following signature:

({
  className: string,
  columnIndex: number,
  column: object
}) => {
  return <td className={className}>{/*...*/}</td>
}

You should return a <td> node (or a Component that renders a td) since this node will be rendered in the tfoot > tr section of the table. You should always pass the className prop.

Utils

reorderColumns

This function is provided as an helper to update the columns array after the columns have been reorderer.

import { reorderColumns } from 'react-infinite-table'

// ...

const newColumns = reorderColumns(oldColumns, fromIndex, toIndex)

Style

You should import the react-infinite-table/dist/style.css file, or if you use scss, you can import the styles as follows:

@import "~react-infinite-table/src/style.scss";

If you want to use the "row selection" feature, you should apply a style on the tr.tr-selected rows as follows:

.react-infinite-table tbody tr.tr-selected td {
  background-color: #007bff;
  border-color: #007bff;
  color: #ffffff;
}

If you use bootstrap, you need to apply the following fixes:

@import "~bootstrap/scss/bootstrap.scss";

// For "Striped" Tables
// by default, bootstrap apply the background color to the <tr>
// and it's a semi-transparent color.

// we need an opaque color
$table-accent-bg: #F2F2F2;

// and we need to apply the backgrounds on td, not on tr!
.table-striped {
  tbody tr:nth-of-type(#{$table-striped-order}) {
    background-color: unset;
  }
  tbody tr:nth-of-type(#{$table-striped-order}) td {
    background-color: $table-accent-bg;
  }
}

// For "Bordered" Tables
// we need to apply the table border on the "wrapper" and not on 
// the <table> so that it is not hidden when scrolling.
.react-infinite-table {
  .table-bordered {
    border: none;
  }
  .react-infinite-table-wrapper {
    border: $table-border-width solid $table-border-color;
  }
}

Development

You can run the demo:

npm start

and make changes to the code. The browser will automatically load the changes.

Contributions

Use GitHub issues for requests.

I welcome pull requests. Please ask first before embarking on any significant pull request, otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project.

Changelog

Changes are tracked in the changelog.

License

react-infinite-table is available under the MIT License.

1.3.0

4 years ago

1.2.3

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.2

4 years ago

1.0.3

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago