# Fixed Data Table 2: a React table that renders only what is on screen

> fixed-data-table-2 is a React table component designed for presenting large amounts of data, with fixed headers and footers, fixed and scrollable columns, variable row heights, column resizing, and a controlled scroll API for touch support. It is a maintained fork of Facebook's original table, and it deliberately leaves layout measurement, sorting, and data fetching to the developer.

**schrodinger/fixed-data-table-2** — A React table component designed to allow presenting millions of rows of data.

- Repository: https://github.com/schrodinger/fixed-data-table-2
- Website: http://schrodinger.github.io/fixed-data-table-2/
- Stars: 1,305 · Forks: 285
- Language: JavaScript
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/schrodinger-fixed-data-table-2

## A fork of a table that stopped being maintained

Fixed Data Table 2 is a continuation of facebook/fixed-data-table, and the reason is stated plainly. The original repo is no longer maintained and has many pull requests awaiting response.

That framing tells you a lot. This is not a new component with a new design, it is a rescue of a good one. The original was a significant piece of work, and the problem with it was not the design but the maintenance, an open repository with a queue of unanswered pull requests and nobody shipping. The fork keeps the API and the behaviour and adds a maintainer.

This version is maintained by Schrödinger, Inc. It is a forked version of Facebook's FixedDataTable repository, available under the BSD License, and contributions and modifications to FixedDataTable are also subject to the BSD License. The repository root carries a `LICENSE` file and a `PATENTS` file, and the contribution terms are spelled out in full: by contributing to FixedDataTable you agree that your contributions will be licensed under the BSD License, and you grant to Schrödinger and any recipients of your contributions a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable licence to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, use, make and distribute them.

The licence field in the repository listing is recorded as custom and unclassifiable by GitHub, which is a side effect of a BSD-derived licence with a patent grant attached.

The releases are steady: v2.0.20 in April 2025, v2.0.21 in May 2025, and v2.0.22 in September 2025, with the last push on 2026-05-23. The package version in the metadata is 2.0.22, and the peer dependencies are react and react-dom at 17.0.1 or newer.

So the situation is a table component with a known API, a working maintainer, and recent releases.

## The component set is three elements, and the data lives outside

Implementing a table involves three component types, `<Table/>`, `<Column/>`, and `<Cell/>`, and the division of responsibility between them is where the design becomes clear.

`<Table />` contains configuration information for the entire table, like dimensions and row count:

```javascript
  const rows =[0,1,2];

  <Table
    rowHeight={50}
    rowsCount={100}
    width={5000}
    height={5050}
    headerHeight={50}
    ...
  </Table>
```

`<Column />` defines the way data is displayed for one column in the table, including all cell behavior for that column. Rather than manipulating each cell directly, you pass a cell component as a prop to the column, and the column renders a cell for each index in the data array:

```javascript
    <Column
      header={<Cell>Col 1</Cell>}
      cell={<Cell>Column 1</Cell>}
      width={2000}
    />
```

The cell components in a column receive the current array index of your data as a prop, `this.props.rowIndex`, and you use that to access the correct value for each cell:

```javascript
    const rows = [0,1,2];
    
    <Column
      header={<Cell>Col 1</Cell>}
      cell={({rowIndex, ...props}) => (
        <Cell {...props}>
        {rows[rowIndex]}
        </Cell>
      )}
      width={2000}
    />
```

And if your data is an array of objects, you define a `columnKey` prop for each column and it too is passed to all cells in that column, so the cell can do `rows[rowIndex][columnKey]`.

The pattern in that last example is the general one. The table knows the row count and the row index, and your cell component knows how to turn that index into a value. The table never looks at your data structure, which is what lets it stay fast and lets the same table work with arrays, objects, or a lazily loaded page.

The row count prop is the crucial one for the large-data case. `rowsCount` is a number, not an array, so the table can be told there are a million rows without a million rows existing in memory.

## What the table deliberately refuses to do

The list of what FixedDataTable does not do is short, specific, and worth reading before you choose it, because each item is work you will have to do.

FixedDataTable does not provide a layout reflow mechanism or calculate content layout information such as width and height of the cell contents. The developer has to provide the layout information to the table instead.

That is the most consequential of the three, and it is a direct consequence of how the table is fast. A component that measures its own content has to read the DOM after every render, and the measurement is what makes a table slow with a large dataset. A table that is told the row height and the column widths never measures anything, and can therefore render a window of rows without touching the layout engine for the ones off screen. The cost is that you cannot have a cell whose height depends on its content, unless you compute that height yourself and pass it in. The feature list names variable row heights with adaptive scroll positions as a supported feature, which means the table can handle varying heights, but the heights still have to come from you.

FixedDataTable does not handle sorting of data. Instead it allows the developer to supply data getters that can be sort-, filter-, or tail-loading-aware.

So sorting is not a prop you set, it is a function you write, and that function is where the sort lives. The same function shape covers filtering and tail loading, which is a neat unification, because in all three cases the table needs to map a row index to a row, and your getter is what does the mapping.

FixedDataTable does not fetch the data, which follows from the previous point.

The three exclusions together describe a component that does one thing extremely well, which is rendering a window of a large dataset at speed, and leaves everything around that to you. If you want a grid with built-in sorting, filtering, and pagination, this is not the component. If you have a fast data layer and a grid that must not drop frames, it is.

## The feature list, and what each one is for

The feature list is a set of nine items, and they fall into two groups.

The layout features are fixed headers and footer, both fixed and scrollable columns, and jumping to a row or column. The last one is a controlled scroll API, and the feature list explains its purpose, that it allows touch support. This is the part of the component that makes it a fixed-data table rather than a table: the first column can stay pinned while the rest scroll, the header stays while the body scrolls, and you can drive the scroll position programmatically.

The data features are handling huge amounts of data, variable row heights with adaptive scroll positions, column resizing, and performant scrolling.

The design goal is stated in the summary as the table being designed to handle thousands of rows of data without sacrificing performance, with scrolling smoothly as a first-class goal, and it is architected in a way to allow for flexibility and extensibility.

The examples directory shows the feature set exercised, and the file names are the feature list in practice. There is `AutoScrollExample.js`, `ColumnGroupsExample.js`, `ColumnGroupsResizeReorderExample.js`, `ContextExample.js`, `DynamicRowHeightExample.js`, `ExpandedExample.js`, `FilterExample.js`, `FixedRightColumnsExample.js`, `FixedRowsExample.js`, `FlexGrowExample.js`, `FooterExample.js`, `HideColumnExample.js`, `InfiniteScrollExample.js`, `LongClickExample.js`, `MaxHeightExample.js`, `ObjectDataExample.js`, `OwnerHeightExample.js`, `PaginationExample.js`, `ReorderExample.js`, `ResizeExample.js`, `ResponsiveExample.js`, `ScrollToColumnExample.js`, `ScrollToRowExample.js`, `SortExample.js`, and `StylingExample.js`.

Several of those filenames are worth pausing on, because they show the component's shape. `FilterExample.js`, `SortExample.js`, `PaginationExample.js`, and `InfiniteScrollExample.js` are the four data-side examples, and they exist precisely because sorting, filtering, pagination, and tail loading are the developer's job, expressed as data getters. `OwnerHeightExample.js` and `DynamicRowHeightExample.js` are the two height examples, and they exist because the height has to be supplied.

`ScrollToRowExample.js` and `ScrollToColumnExample.js` are the controlled scroll API, and `FixedRowsExample.js` and `FixedRightColumnsExample.js` are the fixed positioning. `ColumnGroupsExample.js` covers the header groupings feature.

## The build, the tests, and the browser support table

The package metadata shows a project that has been modernised in its tooling while keeping its API stable.

The package is `fixed-data-table-2` at version 2.0.22, described as a React table component designed to allow presenting thousands of rows of data. The distribution ships only `dist`, with `main` pointing at `dist/cjs/fixed-data-table-2.js` and `module` at `dist/es/fixed-data-table-2.js`, so there is a CommonJS build and an ES module build.

The runtime dependencies are interesting. There is `redux` and `reselect` and `@reduxjs/toolkit`, which is unusual for a table component and tells you the internal state management is built on Redux rather than on React state, with selectors for the derived values. There is `react-portal`, which is how the fixed columns and the header can be rendered outside the scrolling container so they stay in place. `react-lifecycles-compat` is there to support the older lifecycle methods on newer React versions. `lodash` and `prop-types` are the usual two.

The build tooling is Babel and Rollup, with a `rollup.config.js` at the root and a `build_helpers/` directory, and the `.babelrc` at the root shows a Babel 7 setup with the Flow type stripping plugin, which tells you the source was historically written in Flow.

The tests are Jest, with `jest.config.js`, `jest.setup.js`, and a `testRunner.js` at the root, and the `test/` directory. The CI badge points at a workflow named build-and-run-tests, so the build and the tests run together.

The browser support table is the one place the project is blunt about a limitation. Chrome Latest, Firefox Latest, IE 11+, and Safari Unsupported, with a footnote that Safari may function correct but they are not actively testing with it. That is an unusual thing to see in 2026, and it is a real constraint for anyone whose users are on Safari.

The site lives in a `site/` directory and the documentation examples are in `examples/`, and the summary points at the examples section of the documentation site for more detailed examples, recommending create-react-app if you need help getting started with a React build system.

## Where fixed-data-table-2 is the wrong tool

The limits are structural, and they follow directly from the design decisions.

First, if you do not have a large dataset, this is the wrong component. A table with twenty rows does not need fixed headers, a controlled scroll API, column resizing, or a data getter abstraction. You would be paying in configuration complexity, in the fixed layout model, and in a dependency on the project's release cadence, for a table that any grid component renders with less ceremony.

Second, and this is the one that catches teams out, the component will not measure your content. If your cells have variable height, if a cell contains text that wraps, if you want the column width to fit the content, you have to compute those numbers yourself and pass them in. A grid that measures its own content is easier to use and slower, and this component has made that trade deliberately. If your data is heterogeneous, with some rows tall and some short, you are going to write that measurement code.

Third, sorting, filtering, pagination, and loading are all yours. The data getter shape is uniform, which is elegant, but it means the component ships none of the behaviour people expect a table to have. A team that wants a grid and does not want to build filtering should pick a grid that provides filtering.

Fourth, the React version floor and the Safari position. The peer dependencies require react and react-dom at 17.0.1 or newer, so React 16 and below are out, and the Safari column in the support table says Unsupported, with the footnote that it may work but is not actively tested. For an application whose users are mostly on iOS devices, that is a serious consideration rather than a footnote.

Fifth, the dependency set is heavier than a table component's usually is, with Redux, redux-toolkit, and reselect in the runtime dependencies. That is a design consequence rather than a mistake, since the internal state is large and the derived values are expensive, but it does mean the package pulls a state management stack into an application that may not otherwise want one.

Sixth, and this is about the project rather than the component, a fork inherits the original's ecosystem position. The Facebook table is not maintained, but the React ecosystem has moved on, and a component with a fixed-size layout model is somewhat at odds with the direction of the platform, where native overflow and content-visibility do more of the work. The releases are steady and the last push was in May 2026, so the fork is alive, but it is maintaining a design rather than leading one.

## Conclusion

fixed-data-table-2 fits a team with a very large dataset that must render in a scrollable grid, that already owns its data fetching and sorting, and that wants a table which does the windowing for it. It is the wrong choice for a table with a handful of rows, since the fixed layout model costs you real work, and it is the wrong choice for a team that wants a batteries-included grid. Check three things before you adopt it: that you can supply cell layout information, because the component does not measure its own content, that your React is 17.0.1 or newer, and that you are prepared to implement sorting and fetching as data getters rather than expecting the table to do it.

## FAQ

### What is fixed-data-table-2 and what is its relationship to Facebook's table?

It is a React table component for presenting large amounts of data, and it is a continuation of facebook/fixed-data-table, which is no longer maintained and has many pull requests awaiting response. This version is maintained by Schrödinger, Inc., and contributions and modifications to FixedDataTable are also subject to the BSD License.

### What does fixed-data-table-2 not do?

It does not provide a layout reflow mechanism or calculate content layout information such as width and height of the cell contents, and the developer has to provide the layout information. It does not handle sorting of data, instead allowing the developer to supply data getters that can be sort, filter, or tail-loading aware. And it does not fetch the data.

### How do I install and use fixed-data-table-2?

Install it with `npm install fixed-data-table-2` and add the default stylesheet `dist/fixed-data-table.css` using a link tag or import it with a CSS module. A table is built from three components, `<Table/>` for whole-table configuration such as rowHeight, rowsCount, width, and height, `<Column/>` for one column, and `<Cell/>` for the cell content, with `rowIndex` passed to cell components so they can look up the value.

### Which browsers does fixed-data-table-2 support?

The support table lists Chrome Latest, Firefox Latest, IE 11+, and Safari Unsupported, with a footnote that Safari may function correctly but the project is not actively testing with it. The peer dependencies require react and react-dom at 17.0.1 or newer.

## Sources

- [Issues](https://github.com/schrodinger/fixed-data-table-2/issues)
- [Project website](http://schrodinger.github.io/fixed-data-table-2/)
- [README](https://github.com/schrodinger/fixed-data-table-2/blob/master/README.md)
- [Releases](https://github.com/schrodinger/fixed-data-table-2/releases)
- [schrodinger/fixed-data-table-2 on GitHub](https://github.com/schrodinger/fixed-data-table-2)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/schrodinger-fixed-data-table-2
