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");
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.")
);
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}!`;
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>`;
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>
`;
});
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)
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 :)
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
I use t7 only for some POCs where stuff runs in-browser.
React Hpyerscript Helpers are also a nice alternative, with less visual clutter.
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
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
Ah, now that makes sense.
I suppose it's a trade off at end of day. Thanks Marco for your clarification.
This is really cool! I have a few questions for you:
React.createElement, being able to pass in Preact'sh?I'm a huge fan of this! :)
Performance looks like it might have issues:
But I would really like to see this measured to know if it's a problem in practice.
I also read HTM, an alternative to t7, has that recommendation from its creators.
Can you post a link please?
Sure
github.com/developit/htm
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
styleattributes in your post: