Syntax of HTML vs JSX

HTML is the standard language for describing the content of a webpage. Web browsers parse it into a tree of elements called the Document Object Model (DOM) which is used for tracking changes to the webpage’s content after page-load.

JavaScript is the standard language for controlling custom behaviour of a webpage; it can run inside as well as outside the browser.

When developing web front-ends with JavaScript, several popular frameworks (most notably React) enable you to write in a syntax called JSX, which looks like HTML (and has the same purpose, creating DOM elements) but is combined with the powerfulness of JavaScript. JSX is not proper JavaScript and is not supported in browsers, but it’s definitely worth knowing if you’re doing any sort of work with React, Preact, or similar frameworks.

So here’s a list of ways that the syntax of HTML differs from that of JSX. For clarity, I say that HTML/DOM elements have attributes, whereas JSX elements have props (which are used to set the DOM attributes).

(A point about HTML: I give all attributes with double quotes, since that’s my usual style. For many of the examples, it’s permissible to substitute single quotes or not use quotes at all.)

List of differences

Interpolation

Values from JavaScript can be interpolated into JSX using curly brackets.

<p>I’m 27 years old.</p>
<p>I’m {myAge} years old.</p>

Case-sensitivity

Attributes are case-insensitive but props are case-sensitive. So onClick in JSX cannot be written as onclick or ONCLICK as it can in HTML.

<button onclick="doSomething()">Do something</button>
<button onClick={doSomething}>Do something</button>

Hyphenated attributes

Hyphenated attributes correspond to camel-case props. (However, aria-* and data- attributes are exceptions: they stay hyphenated.)

<form accept-charset="utf-8">
<form acceptCharset="utf-8">

There aren’t many camel-case props like this.

class and for

Two attributes are renamed for JSX. They are class and for, which are keywords in JavaScript and therefore cannot be used as the names of JSX props. The JSX equivalents are className and htmlFor.

<label class="action" for="example">
<label className="action" htmlFor="example">

CSS in style object

The style prop can be an object. Note the double curly brackets: the outer curlies are for the interpolation of JavaScript, the inner curlies denote the JavaScript object that is the interpolated value. Camel-casing of hyphenated phrases applies here too.

<h1 style="color: blue; font-size: 2rem">
<h1 style={{color: 'blue', fontSize: '2rem'}}>

Interpolation works here too, of course.

JSX fragments

A JavaScript function cannot return more than one value. For this reason, if you want to return more than one element in JSX, there must always be one element wrapping everything else. We can use fragments (<></>) for this purpose, which make for valid JSX without adding an extra element to the DOM.

<h1>Heading</h1>
<p>Paragraph</p>
<>
	<h1>Heading</h1>
	<p>Paragraph</p>
</>

Fragments can be written more explicitly as <Fragment></Fragment>. This is useful if you want to add props such as key which are used by React but do not become attributes in the HTML (and therefore do not need to be on an HTML element).

<h1>Heading</h1>
<p>Paragraph</p>
<Fragment key={keyForThisFragment}>
	<h1>Heading</h1>
	<p>Paragraph</p>
</Fragment>

Whitespace

Whitespace is treated differently in HTML than in JavaScript. It’s mostly fine. But, if you have a line-break in your JSX before an opening tag, and you want a space to show up before that element, you need to interpolate a space.

<p>
	Hello everyone!
	<a href="aboutme.html">I’m Duncan Ritchie.</a>
</p>
<p>
	Hello everyone!{' '}
	<a href='aboutme.html'>I’m Duncan Ritchie.</a>
</p>

Closing and self-closing tags

Self-closing tags (void elements) are those that cannot have elements inside them. They must be self-closed in JSX.

<br>
<br />

Non-self-closing tags can self-close in JSX.

<a name="section-1" id="section-1"></a>
<a name="section-1" id="section-1" />

Code comments

In HTML, there’s only one syntax for comments, and a comment is a DOM node, so you cannot put it inside another tag.

But in JSX, a comment with // can go at the end of any line, including inside a tag. This makes commenting on a particular attribute easier.

<!-- "text" is the default type for inputs. -->
<!-- enterkeyhint="search" makes a magnifying-glass icon appear on a mobile keyboard. -->
<input
	type="text"
	enterkeyhint="search"
/>
<input
	type="text" // The default type for inputs.
	enterKeyHint="search" // Makes a magnifying-glass icon appear on a mobile keyboard.
/>

You can also use /* */ syntax for JSX comments, as you can in normal JavaScript.

JSX comments created using <!-- --> (the HTML syntax) will appear in the DOM when the browser receives the page. (Of course, comments don’t appear on the rendered page, but they’ll be visible if the visitor uses the browser’s developer tools or “View Page Source” feature.) In contrast, JSX comments in the JavaScript styles only exist in JSX and will not be in the output HTML.

You can read more about comments in JSX in an article by Dmitri Pavlutin.

TypeScript JSX

In the case of numeric props, JSX can accept a JavaScript number (123) or string ('123').

However, JSX can also work with TypeScript. If you’re using JSX with TypeScript (TSX), some props must be numbers, not strings.

<textarea rows="12">
<textarea rows={'12'}>
// or
<textarea rows={12}>
<textarea rows={12}>

Maisie Johnson and Amey Raut both have good articles on JSX.

And of course, you can peruse official documentation, such as for React.

The React docs actually recommend using a HTML-to-JSX conversion tool, rather than manually fixing the things I’ve listed above. I haven’t found the need for a tool like that, but it could be useful if you have huge amounts of HTML you need to put into JSX.