Wrap a Vanilla JavaScript Package for Use in React

Wrap a Vanilla JavaScript Package for Use in React

In this article, I’ll show you how to wrap a 3rd party widget into a React component using ag-Grid as an example. I’ll show you how we set up the mapping between React Props and the widget’s configuration options. You’ll also learn how to expose a widget’s API through a React component.

Complex web projects often require the use of 3rd party widgets. But what if you’re using a framework while a widget is only available in pure JavaScript?

Table of Contents

  • Understanding the JS Widget: Defining things to bridge
  • What should a wrapper component do?
  • React Wrapper Implementation
  • Synchronizing grid properties updates
  • Exposing API
To use a JavaScript widget in your project, the best approach would be to create a framework specific wrapper. That’s what this article is about.

At ag-Grid we focus on developing the fastest and most feature rich JavaScript data grid for web applications. It has no 3rd party dependencies and is specifically designed to deliver outstanding performance even if being used to display millions of records. To make integrations with React applications easier, we’ve implemented our own React grid wrapper.

Understanding the JS Widget: Defining things to bridge

Most widgets can be configured through configuration options. Usually they also define public API and broadcasts events.

In general, most widgets have:

  • Configuration options
  • A public API
  • Broadcasted events

That’s exactly how you interact with ag-Grid. You can find a good description for the grid’s properties, events, callbacks and API here. In short, the datagrid defines:

  • Grid Properties that enable features of the grid, like row animation.
  • Grid API to interact with the grid at runtime, e.g. to get all the selected rows
  • Grid Events emitted by the grid when certain events happen in the grid, like row sorting or rows selection
  • Grid Callbacks used to supply information from your application to the grid when it needs it, e.g. a callback is called each time a menu is shown that allows your application to customize the menu.

Here’s a very basic pure JavaScript configuration that demonstrates the usage of grid options:

let gridOptions = {

// PROPERTIES - object properties, myRowData and myColDefs are created somewhere in your application
rowData: myRowData,
columnDefs: myColDefs,

// PROPERTIES - simple boolean / string / number properties
pagination: true,
rowSelection: 'single',

// EVENTS - add event callback handlers
onRowClicked: function(event) { console.log('a row was clicked'); },
onColumnResized: function(event) { console.log('a column was resized'); },
onGridReady: function(event) { console.log('the grid is now ready'); },

isScrollLag: function() { return false; }


Once the JavaScript data grid is initialized like this:

new Grid(this._nativeElement, this.gridOptions, ...);

ag-Grid attaches the object with API methods to the gridOptions that can be used to control the JavaScript data grid:

// get the grid to refresh
However, when ag-Grid is used as a React component, we don’t instantiate the datagrid directly. That’s the job of the wrapper component.
All interactions with the instance of ag-Grid occurs through the component instance. For example, we don’t have direct access to the API object attached by the grid. We will access it through the component’s instance.

What should a wrapper component do?

We never pass configuration options and callbacks directly to the grid.

A React wrapper component takes the options and callbacks through React Props.

All grid options that are available for vanilla JavaScript grid should be available in React datagrid as well. We also don’t directly listen for events on the instance of ag-Grid. If we’re using ag-Grid as a React component, all events emitted by ag-Grid should be available through React components props.

This all means that a React specific datagrid wrapper around ag-Grid should:

  • implement a mapping between input bindings (like rowData) and ag-Grid’s configuration options.
  • should listen for events emitted by ag-Grid and define them as component outputs
  • listen for changes in component’s input bindings and update configuration options in the grid
  • expose API attached by ag-Grid to the gridOptions through its properties

The following example demonstrates how React datagrid is configured in a template using React Props:


// useful for accessing the component directly via ref

// these are simple attributes, not bound to any state or prop

// these are bound props, so can use anything in React state or props

// this is a callback

// these are registering event callbacks
onGridReady={this.onGridReady.bind(this)}" // inside onGridReady, you receive the grid APIs if you want them


Now that we understand the requirement, let’s see how we implemented it at ag-Grid.

React Wrapper Implementation

First, we need to define a React component AgGridReact that represents our React data grid in templates. This component will render a DIV element that will serve as a container for the datagrid. To get a hold of the native DIV element we use the Refs functionality:

export class AgGridReact extends React.Component {
    protected eGridDiv: HTMLElement;

render() {
    return React.createElement("div", {
        style: ...,
        ref: e =&gt; {
            this.eGridDiv = e;
    }, ...);


Before we can instantiate ag-Grid, we also need to collect all options. All ag-Grid properties and events come as React Props on the AgGridReact component. The gridOptions property is used to store all datagrid options. We need to copy all configuration options from React props as soon as they become available.

To do that, we’ve implemented the copyAttributesToGridOptions function. It’s just a utility function that copies properties from one object to the other. Here’s the gist of the function:

export class ComponentUtil {
    public static copyAttributesToGridOptions(gridOptions, component, ...) {
        // copy all grid properties to gridOptions object
            .forEach(key => {
                if (typeof component[key] !== 'undefined') {
                    gridOptions[key] = component[key];


     return gridOptions;


The options are copied in the componentDidMount lifecycle method after all props have been updated. This is also the hook where we instantiate the grid. We need to pass a native DOM element to the data grid when it’s being instantiated, so we’ll use the DIV element captured using refs functionality. Here’s how it all looks:

export class AgGridReact extends React.Component {
    gridOptions: AgGrid.GridOptions;

componentDidMount() {

    let gridOptions = this.props.gridOptions || {};
    if (AgGridColumn.hasChildColumns(this.props)) {
        gridOptions.columnDefs = AgGridColumn.mapChildColumnDefs(this.props);

    this.gridOptions = AgGrid.ComponentUtil.copyAttributesToGridOptions(gridOptions, this.props);

    new AgGrid.Grid(this.eGridDiv, this.gridOptions, gridParams);

    this.api = this.gridOptions.api;
    this.columnApi = this.gridOptions.columnApi;


You can see above that we also check if there are children that are passed as columns and add then to configuration options as column definitions:

if (AgGridColumn.hasChildColumns(this.props)) {
    gridOptions.columnDefs = AgGridColumn.mapChildColumnDefs(this.props);

Synchronizing grid properties updates

Once the grid is initialized, we need to track changes to React Props to update configuration options of the datagrid. ag-Grid implements API to do that, for example, if the headerHeight property changes there’s the setHeaderHeight method to update the height of a header.

React uses componentWillReceiveProps lifecycle method to notify a component about changes. This is where we put our update logic:

export class AgGridReact extends React.Component {
    componentWillReceiveProps(nextProps: any) {
        const changes = <any>{};
        const changedKeys = Object.keys(nextProps);

    changedKeys.forEach((propKey) =&gt; {
        if (!this.areEquivalent(this.props[propKey], nextProps[propKey])) {
            changes[propKey] = {
                previousValue: this.props[propKey],
                currentValue: nextProps[propKey]
    AgGrid.ComponentUtil.getEventCallbacks().forEach((funcName: string) =&gt; {
        if (this.props[funcName] !== nextProps[funcName]) {
            changes[funcName] = {
                previousValue: this.props[funcName],
                currentValue: nextProps[funcName]

    AgGrid.ComponentUtil.processOnChange(changes, this.gridOptions, this.api, this.columnApi);


Basically we go over the list of ag-Grid’s configuration properties and callbacks and check if any of them have changed. We put all changes in the changes array and then process them using processOnChange method.

The method does two things. First, it goes over the changes in React Props and updates properties on the gridOptions object. Next, it calls API methods to notify the grid about the changes:

export class ComponentUtil {
    public static processOnChange(changes, gridOptions, api, ...) {
        // reflect the changes in the gridOptions object
            .forEach(key => {
                if (changes[key]) {
                    gridOptions[key] = changes[key].currentValue;


    // notify Grid about the changes in header height
    if (changes.headerHeight) {

    // notify Grid about the changes in page size
    if (changes.paginationPageSize) {



Exposing API

Interacting with the React grid at run time is done through the grid API. You may want to adjust the columns size, set new data source, get a list of all selected rows etc. When the JavaScript datagrid is initiated, it attaches the api object to the grid options object. To expose this object, we simply assign it to the component instance:

export class AgGridReact extends React.Component {
    componentDidMount() {
        new AgGrid.Grid(this.eGridDiv, this.gridOptions, gridParams);

    this.api = this.gridOptions.api;
    this.columnApi = this.gridOptions.columnApi;


And that’s it.

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

Follow me on Facebook | Twitter

Learn More

React - The Complete Guide (incl Hooks, React Router, Redux)

Modern React with Redux [2019 Update]

React Native - The Practical Guide

MERN Stack Front To Back: Full Stack React, Redux & Node.js

Build a Basic CRUD App with Node and React

Setting A React Project From Scratch Using Babel And Webpack

JavaScript Basics Before You Learn React

Build a React Calendar Component from scratch

Learn ReactJS with Webpack 4, Babel 7, and Material Design

Using Typescript with modern React (i.e. hooks, context, suspense)

This article was originally published on https://scotch.io

reactjs javascript

What's new in Bootstrap 5 and when Bootstrap 5 release date?

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Random Password Generator Online

HTML Color Picker online | HEX Color Picker | RGB Color Picker

The essential JavaScript concepts that you should understand

The essential JavaScript concepts that you should understand - For successful developing and to pass a work interview

JavaScript Expressions in JSX in ReactJs

Welcome, what is JSX Expressions in React Js in Hindi? JSX is an Expression Too After compilation, JSX expressions become regular JavaScript function calls a...

Grokking Call(), Apply() and Bind() Methods in JavaScript

In this article, we will have a look at the call(), apply() and bind() methods of JavaScript. Basically these 3 methods are used to control the invocation of the function.

ReactJS vs Angular vs Vue: Best Javascript Framework For Your Project

ReactJS vs Angular vs Vue: Best Javascript Framework For Your Project. This video covers the key differences between ReactJS, Angular and Vue with respect to the following: Use case, Performance, Data binding, Scripting language, Testing, Community support, Growth curve

What is JavaScript – All You Need To Know About JavaScript

In this article on what is JavaScript, we will learn the basic concepts of JavaScript.