JSX for web components
Matt Levy
Posted on August 21, 2021
Love it or hate it, JSX is a great technology for rendering HTML using Javascript. It is available for most frameworks but did you know that you can use it for rendering web components too?
You can use JSX with or without transpiling your code.
Without transpiling
Tagged template literals can be used directly in the browser. The htm library provides a JSX-like tagged template literal for rendering HTML.
Here is how you can use it in a FicusJS web component.
import { createCustomElement } from 'ficusjs/custom-element'
import { html, renderer } from '@ficusjs/renderers/htm'
createCustomElement('hello-world', {
renderer,
render () {
return html`<p>Hello world!</p>`
}
})
Template literals are literals delimited with backticks, allowing embedded expressions called substitutions. Tagged template literals call a function (in this case the html
tag function) with an array of any text segments from the literal followed by arguments with the values of any substitutions.
This example uses the @ficusjs/renderers
package which provides a browser-ready ES module using the htm
library.
Clone this Snowpack starter to see it in action - https://github.com/ficusjs/ficusjs-snowpack-starter
With transpiling
As JSX extends Javascript, one of its best features is the ability to transpile it.
Transpiling removes the overhead of loading the renderer and parsing the JSX at runtime. It would be used as a production step to remove the renderer.
The babel-plugin-htm
Babel plugin compiles tagged template literals using htm
to hyperscript. This is the same process React/Preact use in transpiling JSX for production.
Here is an example.
import { h } from '@ficusjs/renderers/jsx-dom'
import { createCustomElement } from 'ficusjs/custom-element'
createCustomElement('hello-world', {
render () {
return html`<p>Hello world!</p>`
}
})
It is very similar to the without transpilation example except that no renderer
function is imported and the h
pragma is imported for transpiling the JSX.
What is the h
pragma?
By default, Babel will transform <p>Hello world!</p>
to React.createElement("p", null, "Hello world!");
. Pragma h
will generate instead as h("p", null, "Hello world!");
.
Pragma is the name to describe the function used by Babel to transpile the JSX.
In this example, pragma h
is the function used by Babel to transpile JSX to Javascript to build the DOM rendered by the component.
By default, the FicusJS web component render
function expects a DOM element for rendering. The pragma imported from the @ficusjs/renderers/jsx-dom
library creates a DOM element for rendering in the component.
This is the output of the transpilation.
import { h } from './_snowpack/pkg/@ficusjs/renderers/jsx-dom.js';
import { createCustomElement } from './_snowpack/pkg/ficusjs/custom-element.js';
createCustomElement('hello-world', {
render() {
return h("p", null, "Hello world!");
}
});
Clone this Snowpack starter to see JSX transpilation in action - https://github.com/ficusjs/ficusjs-compiled-templates
Summary
Using JSX in your web components allows you to use tagged template literals in development and then transpile it away for production resulting in smaller optimised components.
The htm library gives you JSX-like syntax but goes even further.
- Spread props:
<div ...${props}>
instead of<div {...props}>
- Self-closing tags:
<div />
- Components:
<${Foo}>
instead of<Foo>
(whereFoo
is a component reference) - Boolean attributes:
<div draggable />
- No transpiler necessary
- HTML's optional quotes:
<div class=foo>
- Component end-tags:
<${Footer}>footer content<//>
- Syntax highlighting and language support via the lit-html VSCode extension and vim-jsx-pretty plugin
- Multiple root element (fragments):
<div /><div />
- Support for HTML-style comments:
<div><!-- comment --></div>
Try it in your next project!
Posted on August 21, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.