5 min read

React.js was clearly designed with JSX in mind, however, there are plenty of good reasons to use React without it.

Using React as a standalone library lets you evaluate the technology without having to spend time learning a new syntax. Some teams—including my own—prefer to have their entire frontend code base in one compile-to-JavaScript language, such as CoffeeScript or TypeScript. Others might find that adding another JavaScript library to their dependencies is no big deal, but adding a compilation step to the build chain is a deal-breaker.

There are two primary drawbacks to eschewing JSX. One is that it makes using React significantly more verbose. The other is that the React docs use JSX everywhere; examples demonstrating vanilla JavaScript are few and far between. Fortunately, both drawbacks are easy to work around.

Translating documentation

The first code sample you see in the React Documentation includes this JSX snippet:

/** @jsx React.DOM */


<h1>Hello, world!</h1>,



Suppose we want to see the vanilla JS equivalent. Although the code samples on the React homepage include a helpful Compiled JS tab, the samples in the docs—not to mention React examples you find elsewhere on the Web—will not.

Fortunately, React’s Live JSX Compiler can help. To translate the above JSX into vanilla JS, simply copy and paste it into the left side of the Live JSX Compiler. The output on the right should look like this:

/** @jsx React.DOM */


React.DOM.h1(null, "Hello, world!"),



Pretty similar, right?

We can discard the comment, as it only represents a necessary directive in JSX. When writing React in vanilla JS, it’s just another comment that will be disregarded as usual.

Take a look at the call to React.renderComponent. Here we have a plain old two-argument function, which takes a React DOM element (in this case, the one returned by React.DOM.h1) as its first argument, and a regular DOM element (in this case, the one returned by document.getElementById(‘example’)) as its second. jQuery users should note that the second argument will not accept jQuery objects, so you will have to extract the underlying DOM element with $(“#example”)[0] or something similar.

The React.DOM object has a method for every supported tag. In this case we’re using h1, but we could just as easily have used h2, div, span, input, a, p, or any other supported tag. The first argument to these methods is optional; it can either be null (as in this case), or an object specifying the element’s attributes. This argument is how you specify things like class, ID, and so on. The second argument is either a string, in which case it specifies the object’s text content, or a list of child React DOM elements.

Let’s put this together with a more advanced example, starting with the vanilla JS:


React.DOM.input({type:"text", placeholder:"Your name"}),

React.DOM.input({type:"text", placeholder:"Say something..."}),

React.DOM.input({type:"submit", value:"Post"})


For the most part, the attributes translate as you would expect: type, value, and placeholder do exactly what they would do if used in HTML. The one exception is className, which you use in place of the usual class.

The above is equivalent to the following JSX:

/** @jsx React.DOM */

<form className="commentForm">

<input type="text" placeholder="Your name" />

<input type="text" placeholder="Say something..." />

<input type="submit" value="Post" />


This JSX is a snippet found elsewhere in the React docs, and again you can view its vanilla JS equivalent by pasting it into the Live JSX Compiler. Note that you can include pure JSX here without any surrounding JavaScript code (unlike the JSX playground), but you do need the /** @jsx React.DOM */ comment at the top of the JSX side. Without the comment, the compiler will simply output the JSX you put in.

Simple DSLs to make things concise

Although these two implementations are functionally identical, clearly the JSX version is more concise. How can we make the vanilla JS version less verbose? A very quick improvement is to alias the React.DOM object:

var R = React.DOM;


R.input({type:"text", placeholder:"Your name"}),

R.input({type:"text", placeholder:"Say something..."}),

R.input({type:"submit", value:"Post"}))

You can take it even further with a tiny bit of DSL:

var R = React.DOM;

var form = R.form;

var input = R.input;


input({type:"text", placeholder:"Your name"}),

input({type:"text", placeholder:"Say something..."}),

input({type:"submit", value:"Post"})


This is more verbose in terms of lines of code, but if you have a large DOM to set up, the extra up-front declarations can make the rest of the file much nicer to read.

In CoffeeScript, a DSL like this can tidy things up even further:

{form, input} = React.DOM

form {className:"commentForm"}, [

input type: "text", placeholder:"Your name"

input type:"text", placeholder:"Say something..."

input type:"submit", value:"Post"


Note that in this example, the form’s children are passed as an array rather than as a list of extra arguments (which, in CoffeeScript, allows you to omit commas after each line). React DOM element constructors support either approach.

(Also note that CoffeeScript coders who don’t mind mixing languages can use the coffee-react compiler or set up a custom build chain that allows for inline JSX in CoffeeScript sources instead.)


No matter your particular use case, there are plenty of ways to effectively use React without JSX. Thanks to the Live JSX Compiler ’s ability to quickly translate documentation code samples, and the ease with which you can set up a simple DSL to reduce verbosity, there really is very little overhead to using React as a JavaScript library like any other.

About the author

Richard Feldman is a functional programmer who specializes in pushing the limits of browser-based UIs. He’s built a framework that performantly renders hundreds of thousands of shapes in the HTML5 canvas, a writing web app that functions like a desktop app in the absence of an Internet connection, and much more in between


Please enter your comment!
Please enter your name here