Skip to content

JSX/TSX - Custom Content Rendering

JSX (or TSX if you're using TypeScript) is a syntax extension to JavaScript that simplifies template rendering. We highly recommend using JSX/TSX as it will make your development process much easier.

jsx
const MyTemplate = (h, column) =>
  <span style={{ color: 'red' }}>
    <div class="me">{ column.name }</div>
  </span>

While JSX is commonly associated with React, it is not exclusive to it. JSX is simply a way to render content and can be used in any project you choose. We use JSX/TSX in all our projects because it simplifies the rendering process.

For example, consider a regular column header rendered with createElement:

js
const columnTemplate = (createElement, column) => {
  return createElement('span', {
    style: {
      color: 'red'
    },
  }, createElement('div', {
    class: 'me'
  }, column.name));
};
const columns = [{
  name: 'Person name',
  prop: 'name',
  columnTemplate 
}];

Now imagine having 10 or more child nodes. This can quickly become complex. Let's simplify it with JSX or TSX.

WARNING

Remember to escape any HTML code to prevent XSS attacks.

First, create a myJsx.jsx file:

jsx
export const myTemplate = (h, column) => {
  return <span style={{color: 'red'}}>
    <div class="me">{column.name}</div>
  </span>;
}

Then in our main file:

js
import { myTemplate } from `./myJsx`;
const columns = [{
  name: 'Person name',
  prop: 'name',
  columnTemplate: myTemplate
}];

Quite simple, right?

Using Keys in JSX Templates

IMPORTANT

Keys are essential for VNode reconciliation. When rendering lists or dynamic content, always provide unique keys to help the virtual DOM accurately identify, track, and update nodes. Use keys thoughtfully, as incorrect usage can lead to inefficient updates or unexpected behavior.

Keys allow the virtual DOM to:

  • Identify unique nodes - Distinguish between different items even when content is similar
  • Optimize updates - Efficiently update only the nodes that have changed
  • Preserve state - Maintain component state when items are reordered or filtered

Basic Key Usage

When rendering multiple elements, always provide a unique key prop:

jsx
const MyTemplate = (h, props) => {
  const items = props.model.items || [];
  
  return (
    <div>
      {items.map((item, index) => (
        <div key={item.id || `item-${index}`}>
          {item.name}
        </div>
      ))}
    </div>
  );
}

Best Practices for Keys

  1. Use stable, unique identifiers - Prefer IDs from your data over array indices:

    jsx
    // ✅ Good - uses stable ID
    {items.map(item => (
      <div key={item.id}>{item.name}</div>
    ))}
    
    // ⚠️ Acceptable - uses index when no ID available
    {items.map((item, index) => (
      <div key={`item-${index}`}>{item.name}</div>
    ))}
  2. Combine identifiers for uniqueness - When rendering cells, combine row and column identifiers:

    jsx
    const CellTemplate = (h, props) => {
      return (
        <div key={`${props.rowIndex}-${props.colIndex}`}>
          {props.model[props.prop]}
        </div>
      );
    }
  3. Avoid changing keys - Keys should remain stable for the same item across renders:

    jsx
    // ❌ Bad - key changes on every render
    <div key={Math.random()}>Content</div>
    
    // ✅ Good - key is stable
    <div key={props.model.id}>Content</div>

Example: Cell Template with Keys

jsx
const CellWithMultipleItems = (h, props) => {
  const tags = props.model.tags || [];
  
  return (
    <div>
      <span>{props.model.name}</span>
      <div>
        {tags.map(tag => (
          <span key={tag.id} className="tag">
            {tag.label}
          </span>
        ))}
      </div>
    </div>
  );
}

Check out this sample. We use babel-jsx with minimal configuration settings.