jsx
A template tag function for writing JSX-like syntax without a build step.
Syntax
jsx`<div />`jsx`<div>text</div>`jsx`<div class="foo">${children}</div>`jsx`<div class=${className}>${children}</div>`jsx`<${Component} prop=${value}>${children}<//Component>`
Parameters
Interpolations (${}) in the template can appear in several positions:
- Tags -
<${Component}>- Component functions or element names - Attributes -
attr=${value}- Prop values - Children -
>${children}<- Elements, strings, or arrays - Spreads -
...${props}- Object to spread as props
Return value
Element - A Crank element ready to be rendered.
Description
The jsx template tag lets you write JSX-like syntax using JavaScript template literals. It parses the template at runtime and creates Crank elements, providing a build-free alternative to JSX transforms.
Syntax features
- HTML-like syntax: Write elements like
<div>,<span>, etc. - Component interpolation: Use
${Component}as tags - Expression interpolation: Use
${}for values in attributes and children - Self-closing tags:
<br />works as expected - Closing tag shorthand: Use
<//>to close any tag or<//TagName>for explicit closing - Comments: HTML comments
<!-- comment -->are stripped - Spread props:
...${props}in attributes - Whitespace handling: Intelligent whitespace normalization
Caching
Parse results are cached by template string identity, so repeated calls with the same template are efficient.
Examples
Basic usage
import {jsx} from "@b9g/crank/standalone";// Simple elementconst div = jsx`<div class="container">Hello, World!</div>`;// With expressionsconst name = "Crank";const greeting = jsx`<h1>Hello, ${name}!</h1>`;// With attributesconst input = jsx`<input type="text" placeholder="Enter name" />`;
Components
import {jsx} from "@b9g/crank/standalone";function Button({children, onClick}) {return jsx`<button onclick=${onClick}>${children}</button>`;}// Use component with ${} interpolationconst app = jsx`<div><${Button} onClick=${() => alert("Clicked!")}>Click me<//Button></div>`;
Closing tag shorthand
import {jsx} from "@b9g/crank/standalone";// Use </> to close any elementconst element = jsx`<div><span>Content</span><//>`;// Or <//${Component}> for explicit closingfunction Card({children}) {return jsx`<div class="card">${children}</div>`;}const app = jsx`<${Card}><h2>Title</h2><p>Content</p><//Card>`;
Spread props
import {jsx} from "@b9g/crank/standalone";const buttonProps = {class: "btn btn-primary",disabled: false,onclick: () => console.log("clicked"),};const button = jsx`<button ...${buttonProps}>Click</button>`;
Conditional rendering
import {jsx} from "@b9g/crank/standalone";function Greeting({name, showWelcome}) {return jsx`<div>${showWelcome && jsx`<p>Welcome!</p>`}<p>Hello, ${name}!</p></div>`;}
Lists
import {jsx} from "@b9g/crank/standalone";function TodoList({items}) {return jsx`<ul>${items.map(item => jsx`<li key=${item.id}>${item.text}</li>`)}</ul>`;}
Complete application
import {jsx} from "@b9g/crank/standalone";import {renderer} from "@b9g/crank/dom";function* Counter() {let count = 0;for (const props of this) {yield jsx`<div><p>Count: ${count}</p><button onclick=${() => { count++; this.refresh(); }}>Increment</button></div>`;}}renderer.render(jsx`<${Counter} />`,document.getElementById("root"));
With async components
import {jsx} from "@b9g/crank/standalone";async function UserProfile({id}) {const user = await fetchUser(id);return jsx`<div class="profile"><img src=${user.avatar} alt=${user.name} /><h2>${user.name}</h2><p>${user.bio}</p></div>`;}
Escaping
Use backslash to escape special characters:
// Escaped newline (preserved whitespace before)const text = jsx`Line 1 \Line 2`;// Literal ${const literal = jsx`<p>Use \${} for interpolation</p>`;
Error handling
The parser throws SyntaxError for invalid templates:
// Throws: Unmatched opening tag "div"jsx`<div>`;// Throws: Unmatched closing tag "span"jsx`<div></span>`;