Render rich controls with JSX (and JavaScript)

Learn how to render rich controls with JSX and JavaScript.

The typical way to render controls in a frontend extension is with the canva.create method:

canva.create('button', {
id: 'myButton',
label: 'Click me!',
});

But it's also possible to render controls with the JSX syntax:

<Button id="myButton" label="Click me!" key="myButton" />

This tutorial explains how to configure a JavaScript project to support the JSX syntax.

If you're using TypeScript, refer to Render controls with JSX and TypeScript.

Prerequisites

Step 1: Enable JSX compilation

By default, Babel doesn't compile JSX into JavaScript. You need to enable the feature.

To enable JSX compilation, install the @babel/plugin-transform-react-jsx plugin:

npm install @babel/plugin-transform-react-jsx --save-dev
# yarn add @babel/plugin-transform-react-jsx --dev

Then add the plugin to the babel property in the package.json file:

{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-transform-react-jsx"
]
}

If you followed the instructions for setting up a Development URL, these dependencies are already installed and configured.

Step 2: Add the JSX pragma to the source code

At the top of any file that will contain JSX controls, add the follow comment:

/** @jsx canva.create */

During the build process, Babel "sees" this comment and converts the JSX controls into the canva.create syntax.

To see an example of this compilation:

  1. Navigate to the Babel REPL.

  2. In the sidebar, under the Presets heading, select react.

  3. Copy the following code into the editor:

    /** @jsx canva.create */
    <button id="myButton" label="My Button" key="myButton" />

The compiled code resembles the following:

'use strict';
/** @jsx canva.create */
canva.create('button', {
id: 'myButton',
label: 'My Button',
key: '1',
});

Step 3: Use a JSX control

To figure out the JSX syntax for a control, use the following rules:

  1. Use the name of the control as the name of the JSX element.

  2. Define each option — id, label, etc — as a property on the JSX element.

  3. Attach a unique key property to the JSX element.

For example, this is the syntax for creating a Button control with the canva.create method:

canva.create('button', {
id: 'myButton',
label: 'My Button',
});

…and this is the JSX equivalent:

<button id="myButton" label="My Button" key="myButton" />

If a control has a children property, such as the Group control, wrap the JSX element around the children elements:

<group id="group1" label="Group #1" key="group1">
<button id="button1" label="Button #1" key="button1" />
<button id="button2" label="Button #2" key="button2" />
<button id="button3" label="Button #3" key="button3" />
</group>

The canva variable must be available in the same context as the JSX syntax.

(Optional) Step 4: Use pascal case for JSX elements

By default, the names of the JSX elements must be in snake case. Typically though, the names of JSX elements are defined in pascal case.

To use pascal case, define a constant for the name of each control:

const Button = 'button';
const Group = 'group';

Then use the constants as the element names:

<Group id="group1" label="Group #1" key="group1">
<Button id="button1" label="Button #1" key="button1" />
<Button id="button2" label="Button #2" key="button2" />
<Button id="button3" label="Button #3" key="button3" />
</Group>

Step 5: Compile with Babel

To compile the JavaScript, run the build command:

npm run build
# yarn build

In the compiled code, the JSX is replaced with the canva.create method.

Example

/** @jsx canva.create */
const canva = window.canva.init();
canva.onReady(async (opts) => {
renderControls();
});
const renderControls = () => {
const Group = 'group';
const Button = 'button';
const controls = [
<Group id="group1" label="Group #1" key="group1">
<Button id="button1" label="Button #1" key="button1" />
<Button id="button2" label="Button #2" key="button2" />
<Button id="button3" label="Button #3" key="button3" />
</Group>,
];
canva.updateControlPanel(controls);
};