A Brief Introduction to JSX

JSX is language extension for writing the UI logic for your React components. It gets transpiled by Babel to calls to React.createElement. Even though opinions are very polarized about the use of JSX, you’ll find that most React developers really enjoy it. In this post we’ll cover what you need to know to get up and running with writing the UI for React components using JSX.

In case you're wondering, JSX stands for JavaScript XML.

Getting Started

JSX is meant to look a lot like HTML syntax, and is used to describe UIs, which React transforms into DOM elements.

Here’s a simple button component, for example:

function MyButton() {
  return (
    <button id="main-btn" className="btn btn-small">
      Click me!
    </button>
  );
}

It’s not many lines of code, but there’s already a lot going on there, so let’s unpack it! We make use of the native button element and pass in two props: id and className. Normally native attributes keep their name (as with id), but class and for are two reserved keywords in JavaScript. Use className instead of class and htmlFor instead of for. Attributes should also be camel-cased, as in className, and not classname. Non-HTML attributes will be passed-in to the element as props.

We also added the string “Click me!” as the value for the children prop of the button element. You can add anything else that could normally be used within a React element as children, like other components for example.

Behind the scenes, after transpilation, the code will look like this:

function MyButton() {
  return React.createElement(
    "button",
    { id: "main-btn", className: "btn btn-small" },
    "Click me!"
  );
}

Here’s another example with a Card component, which is a class-based component:

class Card extends React.Component {
  render() {
    const { title, content, scale, message } = this.props;
    return (
      <CardWrapper scale={scale}>
        <Header title={title} />
        <Main content={content} />
        <Footer>{message}</Footer>
      </CardWrapper>
    );
  }
}

The above gets transpiled to:

class Card extends React.Component {
  render() {
    const { title, content, scale, message } = this.props;
    return React.createElement(
      CardWrapper,
      { scale: scale },
      React.createElement(Header, { title: title }),
      React.createElement(Main, { content: content }),
      React.createElement(
        Footer,
        null,
        message
      )
    );
  }
}

As you can see, using JSX makes for a terser syntax that’s easy to read and write, especially given that we’re all used to how HTML looks.

JSX as variable value

JSX doesn’t always have to be exclusively used as the return value of a component, and it can be used wherever JavaScript expressions can be used. For example, it’s common to have variables hold some JSX:

function Wrapper() {
  const hello = <h1>Howdy!</h1>;

  return (
    <div>
      {hello}
      <button id="main-btn" className="btn btn-small">
        Click me!
      </button>
    </div>
  );
}

Expressions in curly braces

As you can see from the previous Card component example, JavaScript expressions can be embedded in JSX, by wrapping them in curly braces. This is how values like objects or numbers can be passed-in as props or how we can interpolate values within text content.

Any JavaScript expression can be embedded inside curly braces, so you’ll often see expressions using the ternary operator:

function Wrapper(props) {
  return (
    <div>
      {props.user ? <h2>Hello {props.user.name}</h2> : <h2>Hello stranger!</h2>}
    </div>
  );
}

When a prop or attribute expects an object, the syntax can look confusing at first:

function Wrapper(props) {
  return (
    <div style={{ backgroundColor: "pink", color: "blue" }}>
      {props.children}
    </div>
  );
}

The style attribute expects an object and expressions in JSX need to be wrapped in curly braces, so we wrap the object in curly braces, hence the two sets of curly braces.


All the normal HTML tags can be used in JSX, along with your custom React components. One difference is that component names should be capitalized, and HTML elements should remain all lowercase. For example, notice below how we make use of the div tag and the MyButton component:

function Wrapper() {
  return (
    <div>
      Care to click?
      <MyButton />
    </div>
  );
}

Notice also from the above example how MyButton doesn’t need a closing tag, so it has to be self-closing

Spreading Props

Thanks to the spread operator, props can also be spread onto a React element using JSX:

function ButtonWrapper(props) {
  return (
    <div>
      Care to click?
      <MyButton {...props} />
    </div>
  );
}

Comments in JSX

In case you’re wondering, you’d use comments inside JSX syntax with the /* … */ comment syntax wrapped in curly braces:

function Wrapper() {
  return (
    <div>
      {/* Hoping users will click! */}
      Care to click?
      <MyButton />
    </div>
  );
}

Forcing a Space

We know that HTML has its quicks when it comes to white space. You can use JSX to force a space between two elements:

function Wrapper() {
  return (
    <div>
      Care to click?{' '}
      <MyButton />
    </div>
  );
}

Default Value for Props

Props have a default value of true, so you can just use the prop name in cases where the value passed-in should be true:

function ButtonWrapper() {
  return (
    <div>
      <MyButton large />
      {/* same as... */}
      <MyButton large={true} />
    </div>
  );
}

Keeping React in Scope

One thing that’s important to note is that since behind the scenes JSX gets transpiled to normal function calls to React.createElement, it means that the React library needs to be in scope in the files where you use JSX:

import React from 'react'; // don't forget to import React
import MyButton from './MyButton'; // also import the components you're using

function Wrapper() {
  return (
    <div>
      Hello!
      <MyButton />
    </div>
  )
}

export default Wrapper;

🖖 Now go forth and write some beautiful UIs!

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#