Skip to content

Modus-Logo-Long-BlackCreated with Sketch.

  • Services
  • Work
  • Blog
  • Resources

    OUR RESOURCES

    Innovation Podcast

    Explore transformative innovation with industry leaders.

    Guides & Playbooks

    Implement leading digital innovation with our strategic guides.

    Practical guide to building an effective AI strategy
  • Who we are

    Our story

    Learn about our values, vision, and commitment to client success.

    Open Source

    Discover how we contribute to and benefit from the global open source ecosystem.

    Careers

    Join our dynamic team and shape the future of digital transformation.

    How we built our unique culture
  • Let's talk
  • EN
  • FR

Ext JS to React: Features and Plugins

Published on February 20, 2018
Last Updated on April 23, 2021
Application Development

This is part of the Ext JS to React blog series. You can review the code from this article on the Ext JS to React Git repo.

In our previous articles on React grids, we’ve built a standard grid that allows for sorting and put a pre-built grid library to use to demonstrate row / checkbox selection. These are some of the basic-level features a user would expect from a grid. In this post, we will look at some popular features of the Ext JS grid and explore how to provide the same functionality in our React applications. In this article, as with the Selection Model article, we’ll be leaning on ag-Grid to supply the grid component.

Note: While not a requirement for React, this article’s code examples assume you’re starting with a starter app generated by create-react-app.

ag-Grid Setup

First, we’ll install ag-Grid including the files we’ll use to theme the grid:

npm install --save ag-grid
npm install --save ag-grid-react

If you’re using React 16+ you may also need to install react-dom-factories:

npm install --save react-dom-factories

We will be reusing the same data file that we introduced in the previous article, Basic Grid.

Converting Grid Cell Data

When data is loaded from a remote server, it’s not always what we want to display to our users. Sometimes we want to add something additional to the output. For example, we might want to display a country flag next to someone’s name or render an email address as a clickable link. To do that in Ext JS, we would conventionally use column renderers to return the desired presentation. With ag-Grid, the cellRenderer configuration operates similar to Ext JS’s renderer config option:

import React, { Component } from 'react';
import { AgGridReact } from 'ag-grid-react';
import getData from './data';
import 'ag-grid/dist/styles/ag-grid.css';
import 'ag-grid/dist/styles/ag-theme-material.css';

const { data } = getData();

class App extends Component {
  columns = [
    {
      headerName: 'Name',
      field: 'name'
    },
    {
      headerName: 'Company',
      field: 'company'
    },
    {
      headerName: 'Email',
      field: 'email',
      cellRenderer: params => {
        return `<a href="mailto:${params.value}">${params.value}</a>`;
      }
    }
  ]

  render () {
    return (
      <div className="ag-theme-material">
        <AgGridReact
          containerStyle={{height: '400px'}}
          columnDefs={this.columns}
          rowData={data}
        />
      </div>
    );
  }
}

export default App;
Ext JS to React: Features and Plugins, Controlling Cell Data

Just like with Ext JS, the cellRenderer configuration goes on the column. The arguments, however, are different. In Ext JS, the first argument is the value of the dataIndex for that column and the third argument is the record that correlates to that row. With ag-Grid, the first argument is an object with what you most likely will need such as the value. If you need to use other data from the record, you can use params.data which will give you the full object for that row.

You can review the sample code on the Git repo.

Column Locking

There are times when a grid has lots of data points to present to the user. Columns may overflow the view resulting in horizontal scrolling. However, when a user scrolls they may feel lost. Scrolling will visually disconnect the scrolled-in data from any anchoring column used for reference on the record. Therefore, locking certain columns like a “name” column allows the user to scroll while still seeing the name column so the remaining data feels connected. With Ext JS, a column is locked by setting the column’s locked config to true. With ag-Grid, you use the column’s pinned config:

import React, { Component } from 'react';
import { AgGridReact } from 'ag-grid-react';
import getData from './data';
import 'ag-grid/dist/styles/ag-grid.css';
import 'ag-grid/dist/styles/ag-theme-material.css';

const { data } = getData();

class App extends Component {
  columns = [
    {
      headerName: 'Name',
      field: 'name',
      pinned: 'left'
    },
    {
      headerName: 'Company',
      field: 'company'
    },
    {
      headerName: 'Email',
      field: 'email'
    }
  ]
  
  render () {
    return (
      <div className="ag-theme-material">
        <AgGridReact
          containerStyle={{height: '400px', width: '400px'}}
          columnDefs={this.columns}
          rowData={data}
        />
      </div>
    );
  }
}

export default App;
Ext JS to React: Features and Plugins, Locking Columns

As you can see, the name column sets the pinned config. So the name column will will be pinned (or locked) to the left. A keen eye would notice the pinned config isn’t set to true like with Ext JS. This is because ag-Grid supports something that Ext JS doesn’t: the ability to pin columns to the right as well as the left. As you would expect, if you set pinned to “right“, the column would then be locked to the right side of the grid. You can even pin columns to the left and right sides simultaneously.

You can review the sample code on the Git repo.

Cell Editing

An Ext JS grid wouldn’t be a grid without being able to edit the data right from within the grid! Ext JS made this easy by configuring a plugin on the grid and then setting the editor config (form field) on the column you want to be editable. ag-Grid actually makes this one step easier to enable by simply using the editable config on the target column:

import React, { Component } from 'react';
import { AgGridReact } from 'ag-grid-react';
import getData from './data';
import 'ag-grid/dist/styles/ag-grid.css';
import 'ag-grid/dist/styles/ag-theme-material.css';

const { data } = getData();

class App extends Component {
  columns = [
    {
      headerName: 'Name',
      field: 'name',
      editable: true
    },
    {
      headerName: 'Company',
      field: 'company'
    },
    {
      headerName: 'Email',
      field: 'email'
    }
  ]
  
  render () {
    return (
      <div className="ag-theme-material">
        <AgGridReact
          containerStyle={{height: '400px'}}
          columnDefs={this.columns}
          rowData={data}
        />
      </div>
    );
  }
}

export default App;
Ext JS to React: Features and Plugins, Cell Editing

You can review the sample code on the Git repo.

Custom Cell Editor

After double-clicking on a cell in the “name” column, the text editor will be shown within the cell as you would expect and it only took a single config. The default editor is a text field. While ag-Grid has some other built in editors like a select/combobox editor, you can also easily provide your own editor. First, let’s look at the grid that will reference a custom editor:

import React, { Component } from 'react';
import { AgGridReact } from 'ag-grid-react';
import getData from './data';
import CustomEditor from './CustomEditor';
import 'ag-grid/dist/styles/ag-grid.css';
import 'ag-grid/dist/styles/ag-theme-material.css';

const { data } = getData();

class App extends Component {
  columns = [
    {
      headerName: 'Name',
      field: 'name',
      editable: true
    },
    {
      headerName: 'Company',
      field: 'company'
    },
    {
      headerName: 'Email',
      field: 'email',
      editable: true,
      cellEditorFramework: CustomEditor
    }
  ]
  
  render () {
    return (
      <div className="ag-theme-material">
        <AgGridReact
          containerStyle={{height: '400px'}}
          columnDefs={this.columns}
          rowData={data}
        />
      </div>
    );
  }
}

export default App;

Here, we import the CustomEditor that we will see in a moment. We’ll pass that class to the “email” column using the cellEditorFramework config. Also, notice that the “email” column did still get the required editable config. To build the custom field, we simply have to create a React component. ag-Grid will pass a few things via props that we can use. Here is a simple CustomEditor that renders an email-type input:

CustomEditor Class

import React, { Component } from 'react';

class CustomEditor extends Component {
  state = {}

  componentDidMount () {
    this.refs.input.addEventListener('blur', this.onBlur);
    this.focus();
  }
  componentDidUpdate () {
    this.focus();
  }
  componentWillUnmount () {
    this.refs.input.removeEventListener('blur', this.onBlur);
  }

  focus () {
    // focus the input slightly after dbl-click
    setTimeout(() => {
      const { refs: { input } } = this;
      input.focus();
    });
  }

  get value () {
    let {
      props,
      state: { value }
    } = this;
    if (value == null) {
      value = props.value;
    }
    return value;
  }
  getValue () {
    return this.value;
  }
  onBlur = () => {
    this.props.stopEditing();
  }
  onChange = (event) => {
    this.setState({
      value: event.target.value
    });
  }
  
  render () {
    return <input
      ref="input"
      type="email"
      value={this.value}
      onChange={this.onChange}
      style={{width: "100%"}}
    />;
  }
}

export default CustomEditor;
Ext JS to React: Features and Plugins, Custom Cell Editor

Most of this is normal React. The couple of things ag-Grid provides that we see used here is the value and stopEditing items on the props. The getValue method is an API that ag-Grid will execute as well.

You can review the sample code on the Git repo.

Infinite Scrolling

If you want to render thousands of records, rendering them all to the DOM will likely not perform very well (especially on lower-powered devices). Ext JS uses a buffered renderer plugin that is automatically enabled if the grid has a static size (either from the height / width configs or from a parent layout). The buffered renderer plugin only renders the number of rows that are visible (plus some for a buffer to support smooth scrolling). This enables the DOM to render only a slice of the data to preserve performance. ag-Grid does not enable buffering by default, but does support it with very little code:

import React, { Component } from 'react';
import { AgGridReact } from 'ag-grid-react';
import { dataAsync } from './data';
import 'ag-grid/dist/styles/ag-grid.css';
import 'ag-grid/dist/styles/ag-theme-material.css';

class App extends Component {
  columns = [
    {
      headerName: 'Name',
      field: 'name'
    },
    {
      headerName: 'Company',
      field: 'company'
    },
    {
      headerName: 'Email',
      field: 'email'
    }
  ]
  datasource = {
    async getRows ({ endRow, startRow, successCallback }) {
      // retrieve data
      const data = await dataAsync({
        startRow,
        num: endRow - startRow
      });
      const lastRow = data.total <= endRow ? data.total : -1;
      successCallback(data.data, lastRow);
    }
  }
  
  render () {
    return (
      <div className="ag-theme-material">
        <AgGridReact
          containerStyle={{height: '400px'}}
          columnDefs={this.columns}
          datasource={this.datasource}
          rowModelType="infinite"
        />
      </div>
    );
  }
}

export default App;

All that’s needed is to set the rowModelType prop to “infinite” and provide the datasource. The datasource has a getRows method that enables data retrieval (i.e. from a fetch request) to furnish data for the page the grid requested as the grid is scrolled. If the data is already loaded, you can execute the successCallback function with the slice of data requested.

You can review the sample code on the Git repo.

Conclusion

Grids don’t have to be simple tables of data. They can be a rich, interactive visualization of data as well! Whether it’s parsing data into something more visual or interactive, locking columns, or allowing editing from within the grid and infinite scrolling, using ag-Grid in your React application makes the transition from Ext JS quite easy and in some cases is better than the functionality Ext JS provides. In our next article we’ll take a look at the close relative of the grid, the tree.

Posted in Application Development
Share this

Mitchell Simoens

Mitchell Simoens is a Senior Front End Engineer at Modus Create. Mitchell has spent the last 10 years working with Ext JS including developing core functionality, Sencha Fiddle and (I hope your insurance covers blown minds) supporting the online community with over 40,000 posts on the Sencha Forums. Before working with Ext JS, Mitchell used Perl and PHP but loves spending time with Node JS for today's needs. When not working, you can find Mitchell relaxing with his wife and daughter, or developing his talents as an amateur furniture maker.
Follow

Related Posts

  • React Landing
    Ext JS to React: Migration to Open Source

    Worried about Migrating from Ext JS? Modus has the Answers Idera’s acquisition of Sencha has…

  • Ext JS to React: FAQ
    Ext JS to React: FAQ

    This is part of the Ext JS to React blog series. React is Facebook's breakout…

Want more insights to fuel your innovation efforts?

Sign up to receive our monthly newsletter and exclusive content about digital transformation and product development.

What we do

Our services
AI and data
Product development
Design and UX
IT modernization
Platform and MLOps
Developer experience
Security

Our partners
Atlassian
AWS
GitHub
Other partners

Who we are

Our story
Careers
Open source

Our work

Our case studies

Our resources

Blog
Innovation podcast
Guides & playbooks

Connect with us

Get monthly insights on AI adoption

© 2025 Modus Create, LLC

Privacy PolicySitemap
Scroll To Top
  • Services
  • Work
  • Blog
  • Resources
    • Innovation Podcast
    • Guides & Playbooks
  • Who we are
    • Our story
    • Careers
  • Let’s talk
  • EN
  • FR