Meet JSX...Again!

by kirupa   |   10 October 2016

As you probably noticed by now, we've been using a lot of JSX in the previous tutorials. What we really haven't done is taken a good look at what JSX actually is. How does it actually work? Why do we not just call it HTML? What quirks does it have up its sleeve? In this tutorial, we'll answer all of those questions and more! We will do some serious backtracking (and some forwardtracking!) to get a deeper look at what we need to know about JSX in order to be dangerous.

Onwards!

OMG! A React Book Written by Kirupa?!!

To kick your React skills up a few notches, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions.

BUY ON AMAZON

What Happens with JSX?

One of the biggest thing we've glossed over is trying to figure out what happens with our JSX after we've written it. How does it end up as HTML that we see in our browser? Take a look at the following example where we define a component called Card:

var Card = React.createClass({
  render: function() {
      var cardStyle = {
        height: 200,
        width: 150,
        padding: 0,
        backgroundColor: "#FFF",
        WebkitFilter: "drop-shadow(0px 0px 5px #666)",
        filter: "drop-shadow(0px 0px 5px #666)"
      };

      return (
        <div style={cardStyle}>
          <Square color={this.props.color}/>
          <Label color={this.props.color}/>
        </div>
      );
    }
});  

We can quickly spot the JSX here. It is the following four lines:

<div style={cardStyle}>
  <Square color={this.props.color}/>
  <Label color={this.props.color}/>
</div>

The thing to keep in mind is that our browsers have no idea what to do with JSX. They probably think you are crazy if you ever even try to describe JSX to them. That is why we have been relying on things like Babel to turn that JSX into something the browsers understand: JavaScript.

What this means is that the JSX we write is for human (and well-trained cats) eyes only. When this JSX reaches our browser, it ends up getting turned into pure JavaScript:

return React.createElement(
  "div",
  { style: cardStyle },
  React.createElement(Square, { color: this.props.color }),
  React.createElement(Label, { color: this.props.color })
);

All of those neatly nested HTML-like elements, their attributes, and their children all get turned into a series of createElement calls with default initialization values. Here is what our entire Card component looks like when it gets turned into JavaScript:

var Card = React.createClass({
  displayName: "Card",

  render: function render() {
    var cardStyle = {
      height: 200,
      width: 150,
      padding: 0,
      backgroundColor: "#FFF",
      WebkitFilter: "drop-shadow(0px 0px 5px #666)",
      filter: "drop-shadow(0px 0px 5px #666)"
    };

    return React.createElement(
      "div",
      { style: cardStyle },
      React.createElement(Square, { color: this.props.color }),
      React.createElement(Label, { color: this.props.color })
    );
  }
});  

Notice that there is no trace of JSX anywhere! All of these changes between what you wrote and what our browser sees is part of the transpiling step we've talked about in the Building Your First React App tutorial. That transpilation is something that happens entirely behind-the-scenes thanks to Babel where we've been using it to perform this JSX->JS transformation entirely in the browser. We'll eventually look at using Babel as part of a more-involved build environment where we will just generate a transformed JS file, but more on that when we get there in the future.

But yeah, there you have it. An answer to what exactly happens to all of our JSX. It gets turned into sweet SWEET JavaScript.

JSX Quirks to Remember

As we've been working with JSX, you probably noticed that we ran into some arbitrary rules and exceptions on what you can and can't do. In this section, let's put all of those quirks together in one area and maybe even run into some brand new ones!

You Can Only Return A Single Root Node

This is probably the first quirk we ran into. In JSX, what you return or render can't be made up of multiple root elements:

ReactDOM.render(
  <Letter>B</Letter>
  <Letter>E</Letter>
  <Letter>I</Letter>
  <Letter>O</Letter>
  <Letter>U</Letter>,
  document.querySelector("#container")
);

If you want to do something like this, you need to wrap all of your elements into a single parent element first:

ReactDOM.render(
  <div>
    <Letter>A</Letter>
    <Letter>E</Letter>
    <Letter>I</Letter>
    <Letter>O</Letter>
    <Letter>U</Letter>
  </div>,
  document.querySelector("#container")
);	  

This seemed like a bizarre requirement when we looked at it before, but you can blame createElement for why we do this. With the render and return functions, what you are ultimately returning is a single createElement call (which in turn might have many nested createElement calls). Here is what our earlier JSX looks like when turned into JavaScript:

ReactDOM.render(React.createElement(
  "div",
  null,
  React.createElement(
    Letter,
    null,
    "A"
  ),
  React.createElement(
    Letter,
    null,
    "E"
  ),
  React.createElement(
    Letter,
    null,
    "I"
  ),
  React.createElement(
    Letter,
    null,
    "O"
  ),
  React.createElement(
    Letter,
    null,
    "U"
  )
), document.querySelector("#container"));

Having multiple root elements would break how functions return values and how createElementworks, so that is why you can specify only one return one (root) element! You can now sleep better knowing this.

You Can't Specify CSS Inline

As we saw in the Styling in React tutorial, the style attribute in your JSX behaves differently from the style attribute in HTML. In HTML, you can specify CSS properties directly as values on your style attribute:

<div style="font-family:Arial;font-size:24px">
	<p>Blah!</p>
</div>

In JSX, the style attribute can't contain CSS inside it. Instead, it needs to refer to an object that contains styling information instead:

var Letter = React.createClass({
  render: function() {
      var letterStyle = {
        padding: 10,
        margin: 10,
        backgroundColor: this.props.bgcolor,
        color: "#333",
        display: "inline-block",
        fontFamily: "monospace",
        fontSize: "32",
        textAlign: "center"
      };

      return (
        <div style={letterStyle}>
          {this.props.children}
        </div>
      );
    }
});

Notice that we have an object called letterStyle that that contains all of the CSS properties (in camel-cased JavaScript form) and their values. That object is what we then specify to the style attribute.

Reserved Keywords and className

JavaScript has a bunch of keywords and values that you can't use as identifiers (aka variable or property names). Those keywords look as follows: break, case, class, catch, const, continue, debugger, default, delete, do, else, export, extends, finally, for, function, if, import, in, instanceof, new, return, super, switch, this, throw, try, typeof, var, void, while, with, yield.

When you are writing JSX, you should be careful to not use these keywords as part of any identifiers that you create as well. That can be difficult when certain really popular keywords like class are commonly used in HTML despite also being in JavaScript's reserved keywords list.

Take a look at the following:

ReactDOM.render(
  <div class="slideIn">
    <p class="emphasis">Gabagool!</p>
    <Label/>
  </div>,
  document.querySelector("#container")
);	  

Ignoring JavaScript's reservations about class (like what we've done here) won't work. What you need to do is use the DOM API version of the class attribute called classNameinstead:

ReactDOM.render(
  <div className="slideIn">
    <p className="emphasis">Gabagool!</p>
    <Label/>
  </div>,
  document.querySelector("#container")
);

You can see the full list of supported attributes here, and notice that all of the attributes are camel cased. That detail is important, for using the lowercase version of an attribute won't work. If you are ever pasting a large chunk of HTML that you want JSX to deal with, be sure to go back to your pasted HTML and make these minor adjustments to turn it into valid JSX.

This brings up another point. Because of these minor deviations from HTML behavior, we tend to say that JSX supports an HTML-like syntax as opposed to just saying that JSX supports HTML. This is a deliberate React-ism. The clearest answer to the relationship between JSX and HTML comes from React team member, Ben Alpert, who stated the following as part of a Quora answer:

...our thinking is that JSX's primary advantage is the symmetry of matching closing tags which make code easier to read, not the direct resemblance to HTML or XML. It's convenient to copy/paste HTML directly, but other minor differences (in self-closing tags, for example) make this a losing battle and we have a HTML to JSX converter to help you anyway. Finally, to translate HTML to idiomatic React code, a fair amount of work is usually involved in breaking up the markup into components that make sense, so changing class to className is only a small part of that anyway.

Comments

Just like it is a good idea to comment your HTML, CSS, and JavaScript, it is a good idea to provide comments inside your JSX as well. Specifying comments in JSX is very similar to how you would comment in JavaScript...except for one exception. If you are specifying a comment as a child of a tag, you need to wrap your comment by the { and } angle brackets to ensure it is parsed as an expression:

ReactDOM.render(
  <div class="slideIn">
    <p class="emphasis">Gabagool!</p>
    {/* I am a child comment */}
    <Label/>
  </div>,
  document.querySelector("#container")
);

Our comment in this case is a child of our div element. If you specify a comment wholly inside a tag, you can just specify your single or multi-line comment without having to use the { and } angle brackets:

ReactDOM.render(
  <div class="slideIn">
    <p class="emphasis">Gabagool!</p>
    <Label
      /* This comment
         goes across
         multiple lines */
         className="colorCard" // end of line
    />
  </div>,
  document.querySelector("#container")
);	  

In this snippet, you can see an example of what both multi line comments and a comment at the end of a line looks like. Now that you know all of this, you have one less excuse to not comment your JSX :P

Capitalization, HTML Elements, and Components

Capitalization is important. To represent HTML elements, ensure the HTML tag is lower-cased:

ReactDOM.render(
  <div>
    <section>
      <p>Something goes here!</p>
    </section>
  </div>,
  document.querySelector("#container")
);

When wishing to represent components, the component name must be capitalized:

ReactDOM.render(
  <div>
    <MyCustomComponent/>
  </div>,
  document.querySelector("#container")
);	  

If you get the capitalization wrong, React will not render your content properly. Trying to identify capitalization issues is probably the last thing you'll think about when things aren't working, so keep this little tip in mind.

Your JSX Can Be Anywhere

In many situations, your JSX will not be neatly arranged inside a render or returnfunction like in the examples we've seen so far. Take a look at the following example:

var swatchComponent = <Swatch color="#2F004F"></Swatch>;

ReactDOM.render(
  <div>
    {swatchComponent}
  </div>,
  document.querySelector("#container")
);	  

We have a variable called swatchComponent that is initialized to a line of JSX. When our swatchComponent variable is placed inside the render function, our Swatch component gets initialized. All of this is totally valid, and we will do more such things in the future when we learn how to generate and manipulate JSX using JavaScript.

Conclusion

With this tutorial, we've finally pieced together the various bits of JSX information that the previous tutorials introduced into one location. The most important thing to remember is that JSX is not HTML. It looks like HTML and behaves like it in many common scenarios, but it is ultimately designed to be translated into JavaScript. This means you can do things that you could never imagine doing using just plain HTML. Being able to evaluate expressions or programmatically manipulate entire chunks of JSX is just the beginning. In future tutorials, we'll explore this intersection of JavaScript and JSX further.

If you have a question about this or any other topic, the easiest thing is to drop by our forums where a bunch of the friendliest people you'll ever run into will be happy to help you out!

THE KIRUPA NEWSLETTER

Get cool tips, tricks, selfies, and more...personally hand-delivered to your inbox!

( View past issues for an idea of what you've been missing out on all this time! )

WHAT DO YOU THINK?

NEWSLETTER

No spam. No fluff. Just awesome content sent straight to your inbox!

Awesome and high-performance web hosting!
BACK TO TOP
new books - yay!!!