React & CoffeeScript

Multiple people asked what's the story about JSX and CoffeeScript. There is no JSX pre-processor for CoffeeScript and I'm not aware of anyone working on it. (If you are interested in writing one, you probably should look at CoffeeScriptRedux). Fortunately, CoffeeScript is pretty expressive and we can play around the syntax to come up with something that is usable.

Example

Let's see how JSX look like with an example:

<div className="MarkdownEditor">
  <h3>Input</h3>
  <textarea onKeyUp={this.handleKeyUp} ref="textarea">
    {this.state.value}
  </textarea>
</div>

which desugars to the following

React.DOM.div({className: 'MarkdownEditor'}, [
  React.DOM.h3({}, 'Input'),
  React.DOM.textarea({onKeyUp: this.handleKeyUp, ref: 'textarea'},
    this.state.value
  )
])

We can easily translate it to CoffeeScript:

{div, h3, textarea} = React.DOM
(div {className: 'MarkdownEditor'}, [
  (h3 {}, 'Input'),
  (textarea {onKeyUp: @handleKeyUp, ref: 'textarea'},
    @state.value
  )
])

Structure

The translations rules are really easy. The only gotcha is to write the tags wrapped in parenthesis lisp-style. This is the best way I found not to get caught with indentation issues.

# Empty element
# <div></div>
(div {})
 
# Text children: You use a string literal
# <div>foo</div>
(div {}, 'foo')
 
# Interpolation: You ignore the {} and write the expression as is
# <div>{this.state.text}</div>
(div {}, @state.text)
 
# Multiple children: You use the [] notation
# <div>
#  <br />
#  <br />
# </div>
(div {}, [
  (br {}),
  (br {})
])
 
# Attributes: You write them using {} notation
# <div onClick={this.onClick}></div>
(div {onClick: @onClick})

Demos

I've re-written all the React front-page examples using CoffeeScript. The translation was really easy.

Hello World

Timer

Todo

Markdown

If you liked this article, you might be interested in my Twitter feed as well.
 
  • Zack Gomez

    neat!

  • Myron

    Why not to use code like this:

    HelloMessage = React.createClass
    render: ->
    `{'Hello ' + this.props.name}`

    React.renderComponent ``, mountNode

    ?

  • Myron

    (sorry for corrupted formatting)

  • sankalp singha

    Thank you for this!! Really really informative!!

  • sankalp singha

    I have got this code :

    var Comment = React.createClass({
    render: function() {
    return (

    {this.props.author}

    {this.props.children}

    );
    }
    });

    How will this be converted into CS?
    I tried this, but I guess I am wrong somewhere?

    comment = React.createClass
    render : ->
    (div {className : "comment"},[ h2 {className : "commentAuthor"},[@props.author]])

  • http://tiye.me/ 题叶

    How about my solution for the HTML part? https://github.com/jiyinyiyong/coffee-html

  • Vincent Lecrubier

    Great ! I made the TodoMVC example using react + coffee script as explained here.

    https://github.com/crubier/todomvc-react-coffee

  • michaelbylzztra

    I like this much better than the suggested syntax in the hacker news article https://news.ycombinator.com/item?id=7232695. Perhaps only because I've done some Clojure though - it's quite similar. Very clever use of coffeescript.

  • Joakim Ekberg ☁

    Thanks for a great post!

    I've used your trick when hacking React.js in CoffeeScript. However, one thing that annoyed me was the requirement of having an empty object if you didn't want to pass any options to a tag.

    I've just published a post on how to get around that and to write tags without the empty object like this:

    h1, "foobar"
    h2, {className: "foo"}, "bar"

    https://medium.com/tictail-makers/replacing-jsx-with-vanilla-coffeescript-4d3ef5eccae4

  • Sachel McNellie

    Those {} really add up to a bunch of clutter. Thank you for this wonderful little hack.

  • Joakim Ekberg ☁

    You're welcome!

 

Related Posts

  • August 27, 2011 Start a technical blog, it’s worth it! (3)
    Lately, I've been advocating to all my student friends to start a blog. Here's an article with the most common questions answered :) What are the benefits? Being known as an expert. The majority of my blog posts are about advanced Javascript topics. As a result, I'm being tagged as the "Jav...
  • September 17, 2011 WoW Interface Anchor Positioning (5)
    I've always found CSS positioning with both float and position: absolute/relative hard to work with. I want to introduce to you an alternative way borrowed from the World of Warcraft Interface: Anchors. Anchor The concept is extremely simple. You can tell where you want the element to be, rel...
  • November 5, 2011 Simulated Annealing Project (0)
    For a school project, I have to implement Simulated Annealing meta heuristic. Thanks to many open source web tools, I've been able to quickly do the project and have a pretty display. CoffeeScript, Raphael, Highcharts, Three.js, Twitter Bootstrap, jQuery and Web Workers. .hover-border img {...
  • December 7, 2011 Automatic Links with Trie (0)
    On MMO-Champion, we often paste World of Warcraft patch notes taken from Blizzard. The main problem is that it's plain text. We want to be able to add links to all the spells, quests, zones ... This way people can mouseover and see the description. It helps figuring out what changed. We create...
  • July 4, 2013 JSX for the real DOM (3)
    React is bundled with a Javascript transpiler called JSX. It gives the ability to write <html> tags within Javascript. The advertised way to use JSX is React.DOM to create React light DOM elements, but it is not the only way. We can create another JSX backend, called JSXDOM, to create real DOM...