DEV Community

K
K

Posted on

React Without JSX, t7 To The Rescue!

TL;DR Here is a repository with a working example. :)

Why Not JSX

When using React, the default way to do things is JSX. It's a nice syntax extension for JavaScript and helps to get rid of the whole React.createElement() cruft you would end up without it. It compiles down to simple function calls and is not as much magic as one would expect.

Problem with this approach, you need to pre-process your JavaScript before you can deliver it to your clients. While most developers who use JavaScript do this anyway, because of Flow or fancy ES20thingamabob syntax extensions, this might not be your cup of tea.

Luckily JSX compiles down to simple function calls, so you can get away without it.

How To Use React Without JSX

One way is to simply use the function that is called, namely React.createElement.

// JSX
const title = <h1>Hello, World!</h1>;

// JS
const title = React.createElement("h1", null, "Hello, world1");
Enter fullscreen mode Exit fullscreen mode

It's the easiest way, but it comes at a cost: The code size gets out of hand rather quick, even with simple markup.

// JSX
const content = (
  <div>
   <p>A paragraph of text.</p>
   <p>Another paragraph, with different text</p>
  </div>
);

// JS
const content = React.createElement("div", null,
  React.createElement("p", null, "A paragraph of text."),
  React.createElement("p", null, "Another paragraph of different text.")
);
Enter fullscreen mode Exit fullscreen mode

Also, you lose a feature of JSX (which I like rather much): Scanning your code for markup, because it doesn't stick out as much anymore.

How To Use t7 Instead

Another way is a small library called t7. It uses a rather young feature of JavaScript called tagged template literals. These are functions that can be called by simple creating a prefixed template literal.

// Template Literal With Place Holder
const expression = 'World'
const text = `Hello, ${expression}!`;

// Tagged Template With Place Holder
const expression = 'World'
const text = somePrefix`Hello, ${expression}!`;
Enter fullscreen mode Exit fullscreen mode

The difference between both is, that the second will pass the whole template content into a function called somePrefix that can do something with it.

t7 now is such a function. It implements a parser that can read JSX-like syntax inside a string template and convert it into regular function calls. For example to React.createElement.

// JSX
const expression = 'World'
const text = <h1>Hello, {expression}!</h1>;

// t7
const expression = 'World'
const text = t7`<h1>Hello, ${expression}!</h1>`;
Enter fullscreen mode Exit fullscreen mode

Notice that JSX uses {} for expressions and template literals use ${}.

Nice, hu?

But this isn't all. t7 also allows you to create and register components, the bread and butter of every React application!

// JSX
const MyButton = props => (
  <div onClick={props.onClick} style={{background: "#ff0"}}>
    Hello, World!
  </div>
);

const Application = () => (
  <div>
    <MyButton onClick={() => alert("!")} />
  </div>
);

// t7
t7.module(t7 => {
  const MyButton = props => t7`
    <div onClick=${props.onClick} style=${{background: "#ff0"}}>
      Hello, World!
    </div>
  `;
  t7.assign("MyButton", MyButton); 

  const Application = () => t7`
    <div>
      <MyButton onClick=${() => alert("!")} />
    </div>
  `;
});
Enter fullscreen mode Exit fullscreen mode

Components can be created almost like with JSX, but you have to register them with t7.assign, this call has to be inside a t7.module callback and the component will only be available inside this callback to prevent creating global components.

Conclusion

t7 is a easy way to write markup inside of JavaScript without the need of JSX and its extra compiler. It leverages new ES2015 features to accomplish this. The result is completely valid JavaScript and you still find your markup rather quick while scanning the source.

Top comments (12)

Collapse
 
josegonz321 profile image
Jose Gonzalez

Hmmm...interesting. This looks rather promising.

Some observations:

Backticks
I know, I am nick-picking. But I feel like they add unnecessary noise. And also ${}. :(

JSX
One reason I love JSX is due to its simplicity. I'm using psuedo-HTML but feels right. I like its simplicity and elegance. It's much less noisy than adding ng-* for sure. JSX is the reason why I enjoyed playing around with React far more than Angular.

Not a big deal? In small projects, it's not. But when you have a huge code base maintained by multiple devs, code readability (and simplicity) is king.

TSX
I'd love to know your opinion on TSX :)

Collapse
 
rnvdrs profile image
Rony Vidaur

I totally agree with your comment about JSX and its simplicity and the unnecessary noise that the t7 syntax would add affecting the readability :)

Although it's always nice to have options I think I'll stick with JSX for now

Collapse
 
kayis profile image
K

I use t7 only for some POCs where stuff runs in-browser.

React Hpyerscript Helpers are also a nice alternative, with less visual clutter.

Collapse
 
kayis profile image
K

I like TypeScript very much, but I have the feeling that FB will push Flow or ReasonML much harder in the future, so I don't know if TS(X) can guarantee the same dev experience in the future, especially for things like React-Native.

On the other hand is MS embracing RN with ReactXP, so who knows :D

Collapse
 
marcoms profile image
Marco Scannadinari

The backticks and ${} syntax are natively part of ES2015, defined as 'template literals'. t7 uses these so that you don't need to use an additional preprocessor/transpiler

Collapse
 
josegonz321 profile image
Jose Gonzalez

Ah, now that makes sense.

I suppose it's a trade off at end of day. Thanks Marco for your clarification.

Collapse
 
antjanus profile image
Antonin J. (they/them)

This is really cool! I have a few questions for you:

  1. Can you specify a different method of element creation? Eg. instead of using React.createElement, being able to pass in Preact's h?
  2. What's the performance like? I feel like it must be pretty good especially compared to the old school in-browser JSX compilation.
  3. Do you have this on a CDN anywhere? I think this is would be awesome for using in CodePen or similar rapid prototyping tools

I'm a huge fan of this! :)

Collapse
 
toomim profile image
Michael Toomim

Performance looks like it might have issues:

It's highly recommended that the t7-precompiler is used when deploying to a production environment. The precompiler will greatly reduce memory usage, startup speeds and template compile times.

github.com/trueadm/t7#performance

But I would really like to see this measured to know if it's a problem in practice.

Collapse
 
kayis profile image
K

I also read HTM, an alternative to t7, has that recommendation from its creators.

Thread Thread
 
toomim profile image
Michael Toomim

Can you post a link please?

Thread Thread
 
kayis profile image
K
Collapse
 
ryaninvents profile image
Ryan Kennedy

This is really neat! Lately I've been looking for an example of a "partial" parser (parser that is aware of "holes" such as template interpolations or a user's cursor in an input field) and this is a great one 😃

Small note, I think there's an interaction between the template string syntax and the dev.to markdown parser affecting the style attributes in your post:

`style` attribute values are missing the double-curly-braces in both examples