JSX Made Simple: Learn the 3 Essential Rules

JSX Made Simple: Learn the 3 Essential Rules

·

3 min read

If you're writing React today, you're probably using JSX.

If you aren't familiar with JSX, it can be challenging to work with at first. For the most part, it should resemble HTML, but there are some subtle differences. Understanding these differences and the JSX ruleset will help you write better React code.

These are 3 rules you need to keep in mind.

1. You must return a single root element

When you return JSX from a functional React component, it must be a single element.

This has to do with how JavaScript handles return statements. In JavaScript, you can't return more than one thing from a function.

Let's look at an example:

// Wrong
function getName() {
    const firstName = 'John';
    const lastName = 'Doe';
    return firstName lastName;
}

// Correct
function getName() {
    const firstName = 'John';
    const lastName = 'Doe';
    return [firstName, lastName];
}

In this example, the function getName returns a firstName and a lastName. Since this is JavaScript, there's no way to return both values directly. To get around this, you can wrap both values before returning them.

One way to wrap the values is with an array.

JSX works the same way.

While JSX might look like HTML, it's a bit different. When you build your React code to be distributed to users, the JSX gets converted to function calls that return objects. You can read my blog post about how React converts JSX to HTML to learn more.

Since the JSX ultimately gets converted into an object at runtime, it must abide by the same JavaScript rules:

function MyComponent() {
    return <div id="my-id">My Component</div>;
}

// The code above gets converted to:
function MyComponent() {
    return React.createElement(
        'div',
        { id: 'my-id' },
        'My Component'
    );
}

// The code above can be replaced with the following
// (createElement returns an object)
function MyComponent() {
    return {
        'type': 'div',
        'key': null,
        'ref': null,
        'props': {
            'id': 'my-id',
            'children': 'My Component'
        },
        '_owner': null,
        '_store': {}
    };
}

So what do you do when you need to return multiple JSX elements?

Multiple JSX elements can be wrapped with a Fragment

React provides a workaround with the Fragment syntax. A Fragment is an empty JSX tag that can wrap other JSX elements. Fragments render their children directly without wrapping them in a separate HTML tag:

function MyComponent() {
    return (
        <>
            <div>Child One</div>
            <div>Child Two</div>
        </>
    );
}

2. All JSX tags must be closed

For most HTML elements, (e.g. div) this should feel natural.

However, some HTML tags don't have a closing tag. For those elements or for custom components that don't have children, things will feel a bit different. When you write the tag in JSX, you'll need to use a self-closing tag:

function MyComponent() {
    return <img src="./myimg.png" alt="My Image" />;
}

function App() {
    return <MyComponent />;
}

Note: All JSX elements can be self-closing, including the <div /> tag:

3. Most JSX attributes and values use camelCase

Most attributes used with JSX elements resemble their counterparts that are used with HTML elements.

However, this doesn't always translate correctly since JSX is eventually converted into JavaScript objects. The JSX attributes become object properties. In JavaScript, it's a common pattern to read object properties into variables (e.g. destructuring):

const { myProp } = { myProp: 10 };
console.log(myProp); // 10

These variables have limitations in terms of what they can be named. They can't be reserved keywords or have dashes. Because of this limitation, these attributes are typically named/renamed using camel-case.

Here are a few examples:

  • The font-weight property in the style object becomes fontWeight

  • The reserved keyword class becomes className

  • tabindex becomes tabIndex

That last one should be fine either way, but I assume it's camel-cased to ensure consistency between the attributes.

You can get the full list of these attributes here.