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!

  • Dylan Piercey

    Thanks for this little helper function. It basically is the reason I am trying react right now (syntax was being a pain). I have condensed it a little further if anyone wants to use.

    DOM = do ->

    object = {}

    for tag in Object.keys(React.DOM)

    object[tag] = do (tag)-> (options...)->

    options.unshift null unless typeof options[0] is 'object'

    React.DOM[tag].apply? @, options

    object

  • http://tiye.me/ 题叶
  • Dylan

    This has inspired me to make my own framework similar to react but that works seamlessly with coffeescript.

    http://redd.it/2futf2 Here is my current syntax. (Currently pre beta). You should let me know what you think.

  • Dylan

    I have been working on a project called French Press and would love more suggestions and feedback to improve it further.

    It's based on the principles of react but with some other benefits and it's designed with coffee-script in mind.

    https://github.com/DylanPiercey/FrenchPress

  • domachine

    Just launched a tool to convert html to this kind of coffeescript driven reactjs: http://html2coffee-react.s3.domachine.de

  • http://btylerburton.com b.tyler.burton

    When I remove `React.autoBind` from the right-hand side of the function the coffeescript compiles. But yours seem to render fine in JSFiddle with that left in. Why?

  • Max Hoffman

    Thanks Joakim for your tip. After implementing your hack I have to put a comma after each tag. Can I get rid of the comma too?

  • Joakim Ekberg ☁

    I think that you still need it, just because it's CoffeeScript syntax, but if you find a way around it please let me know!

  • Max Hoffman

    Joakim, I don't understand how i can use owned components? Like this http://facebook.github.io/react/docs/multiple-components.html

    I have 2 components, main and secondary. But i don't know how i should write component name ( React.renderComponent `` ) using your method react+coffee. Tell me pls.

 

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 (5)
    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...