React Data Grid Cell renderer

Overview

A renderer is a function that determines how a cell looks.

Set together, a renderer, editor and validator form a cell type.

Declaring a custom renderer as a component

Handsontable's React wrapper lets you create custom cell renderers using React components. Although it's possible to use class-based react components for this purpose, we strongly suggest using functional components, as using the state of a class-based component would re-initialize on every Handsontable render.

To mark a component as a Handsontable renderer, simply add a hot-renderer attribute to it.

TIP

Handsontable's autoRowSize and autoColumnSize options require calculating the widths/heights of some of the cells before rendering them into the table. For this reason, it's not currently possible to use them alongside component-based renderers, as they're created after the table's initialization.

Be sure to turn those options off in your Handsontable configuration, as keeping them enabled may cause unexpected results. Please note that autoColumnSize is enabled by default.

    Using the renderer component within React's Context

    In this example, React's Context passes information available in the main app component to the renderer. In this case, we're using just the renderer, but the same principle works with editors as well.

      Declaring a custom renderer as a function

      You can also declare a custom renderer for the HotTable component by declaring it as a function. In the simplest scenario, you can pass the rendering function as a Handsontable setting.

      The following example implements @handsontable/react with a custom renderer added. It takes an image URL as the input and renders the image in the edited cell.

        TIP

        All the sections below describe how to utilize the features available for the Handsontable function-based renderers.

        Overview

        When you create a renderer, a good idea is to assign it as an alias that will refer to this particular renderer function. Handsontable defines 10 aliases by default:

        • autocomplete for Handsontable.renderers.AutocompleteRenderer
        • base for Handsontable.renderers.BaseRenderer
        • checkbox for Handsontable.renderers.CheckboxRenderer
        • date for Handsontable.renderers.DateRenderer
        • dropdown for Handsontable.renderers.DropdownRenderer
        • html for Handsontable.renderers.HtmlRenderer
        • numeric for Handsontable.renderers.NumericRenderer
        • password for Handsontable.renderers.PasswordRenderer
        • text for Handsontable.renderers.TextRenderer
        • time for Handsontable.renderers.TimeRenderer

        It gives users a convenient way for defining which renderer should be used when table rendering was triggered. User doesn't need to know which renderer function is responsible for displaying the cell value, he does not even need to know that there is any function at all. What is more, you can change the render function associated with an alias without a need to change code that defines a table.

        TIP

        You can set a cell's renderer, editor or validator individually, but you still need to set that cell's type. For example:

        renderer: Handsontable.NumericRenderer,
        editor: Handsontable.editors.NumericEditor,
        validator: Handsontable.NumericValidator,
        type: 'numeric'
        

        Using a cell renderer

        It is possible to register your renderer and re-use it with the name you registered it under.

        <HotTable
          data={someData}
          columns={[{
            renderer: 'numeric'
          }]}
        />
        

        Registering custom cell renderer

        To register your own alias use Handsontable.renderers.registerRenderer() function. It takes two arguments:

        • rendererName - a string representing a renderer function
        • renderer - a renderer function that will be represented by rendererName

        If you'd like to register asterixDecoratorRenderer under alias asterix you have to call:

        Handsontable.renderers.registerRenderer('asterix', asterixDecoratorRenderer);
        

        Choose aliases wisely. If you register your renderer under name that is already registered, the target function will be overwritten:

        Handsontable.renderers.registerRenderer('text', asterixDecoratorRenderer);
        

        Now 'text' alias points to asterixDecoratorRenderer function, not Handsontable.renderers.TextRenderer.

        So, unless you intentionally want to overwrite an existing alias, try to choose a unique name. A good practice is prefixing your aliases with some custom name (for example your GitHub username) to minimize the possibility of name collisions. This is especially important if you want to publish your renderer, because you never know aliases has been registered by the user who uses your renderer.

        Handsontable.renderers.registerRenderer('asterix', asterixDecoratorRenderer);
        

        Someone might already registered such alias

        Handsontable.renderers.registerRenderer('my.asterix', asterixDecoratorRenderer);
        

        That's better.

        Using an alias

        The final touch is to using the registered aliases, so that users can easily refer to it without the need to now the actual renderer function is.

        To sum up, a well prepared renderer function should look like this:

        function customRenderer(hotInstance, td, row, column, prop, value, cellProperties) {
          // Optionally include `BaseRenderer` which is responsible for
          // adding/removing CSS classes to/from the table cells.
          Handsontable.renderers.BaseRenderer.apply(this, arguments);
        
          // ...your custom logic of the renderer
        }
        
        // Register an alias
        Handsontable.renderers.registerRenderer('my.custom', customRenderer);
        

        From now on, you can use customRenderer like so:

        <HotTable
          data={someData}
          columns={[{
            renderer: 'my.custom'
          }]}
        />
        

        Rendering custom HTML in cells

        This example shows how to use custom cell renderers to display HTML content in a cell. This is a very powerful feature. Just remember to escape any HTML code that could be used for XSS attacks. In the below configuration:

        • Title column uses built-in HTML renderer that allows any HTML. This is unsafe if your code comes from untrusted source. Take notice that a Handsontable user can use it to enter <script> or other potentially malicious tags using the cell editor!
        • Description column also uses HTML renderer (same as above)
        • Comments column uses a custom renderer (safeHtmlRenderer). This should be safe for user input, because only certain tags are allowed
        • Cover column accepts image URL as a string and converts it to a <img> in the renderer

          Rendering custom HTML in header

          You can also put HTML into row and column headers. If you need to attach events to DOM elements like the checkbox below, just remember to identify the element by class name, not by id. This is because row and column headers are duplicated in the DOM tree and id attribute must be unique.

            Adding event listeners in cell renderer function

            If you are writing an advanced cell renderer, and you want to add some custom behavior after a certain user action (i.e. after user hover a mouse pointer over a cell) you might be tempted to add an event listener directly to table cell node passed as an argument to the renderer function. Unfortunately, this will almost always cause you trouble and you will end up with either performance issues or having the listeners attached to the wrong cell.

            This is because Handsontable:

            • calls renderer functions multiple times per cell - this can lead to having multiple copies of the same event listener attached to a cell
            • reuses table cell nodes during table scrolling and adding/removing new rows/columns - this can lead to having event listeners attached to the wrong cell

            Before deciding to attach an event listener in cell renderer make sure, that there is no Handsontable event that suits your needs. Using Handsontable events system is the safest way to respond to user actions.

            If you did't find a suitable Handsontable event put the cell content into a wrapping <div>, attach the event listener to the wrapper and then put it into the table cell.

            Performance considerations

            Cell renderers are called separately for every displayed cell, during every table render. Table can be rendered multiple times during its lifetime (after table scroll, after table sorting, after cell edit etc.), therefore you should keep your renderer functions as simple and fast as possible or you might experience a performance drop, especially when dealing with large sets of data.