jsx-standalone makes it possible to use React's JSX syntax outside of React projects. Using renderBefore and renderAfter requires a modern browser supporting Element.insertAdjacentElement() - all other render modes function in legacy browsers.
yarn add jsx-standaloneYou'll also need to hook the jsxElem function into the JSX transformation, for which you should probably use babel, which you can install and setup fairly simply:
yarn add @babel/preset-react @babel/preset-envand configure babel to correctly transform JSX with a .babelrc something like:
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-react",
{
"pragma": "jsxElem.createElement",
"pragmaFrag": "jsxElem.Fragment"
}
]
]
}
Details on how to inject jsxElem as builder can be found in the esbuild documentation. Feel free to open a PR to add specific instructions here.
The jsx-standalone package just defines a function to replace the React.createElement, so as well as importing the relevant function into scope where you want to use JSX:
import jsxElem, { render } from "jsx-standalone";
function App(props) {
return <div>Hello {props.name}</div>;
}
render(<App name="world" />, document.body);or
import jsxElem, { render } from "jsx-standalone";
function App(name) {
return <div>Hello {name}</div>;
}
render(App("world"), document.body);It's possible to define a component in different ways:
function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
// anonymous Function
const Hello = function(props) {
return <h1>Hello {props.name}</h1>;
};
// arrow function
const Hello = props => <h1>Hello {props.name}</h1>;
// simple element
const hello = <h1>Hello</h1>;Always start component names with a capital letter.
babel-plugin-transform-react-jsx treats components starting with lowercase letters as DOM tags. For example <div /> is an HTML tag, but <Hello /> is a component and requires a user definition.
Please read JSX In Depth for more details and try babel example
When rendering a component JSX attributes will be passed as single object.
For example:
import jsxElem, { render } from "jsx-standalone";
function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
render(<Hello name="world" />, document.body);There are several ways to render an element:
renderBefore: this function renders the JSX element before the target - top level JSX element must not be a fragment.renderPrepend: this function renders the JSX element within the target element, prepending existing content in the target element.render: replaces the contents of the target element with the JSX element.renderAppend: this function renders the JSX element within the target element, appending existing content in the target element.renderAfter: this function renders the JSX element after after the target element - top level JSX element must not be a fragment.
import jsxElem, { render, renderAfterEnd, renderBeforeEnd, renderAndReplace } from "jsx-standalone";
function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
renderBefore(<Hello name="world" />, document.body);
renderPrepend(<Hello name="world" />, document.body);
render(<Hello name="world" />, document.body);
renderAppend(<Hello name="world" />, document.body);
renderAfter(<Hello name="world" />, document.body);Components can be reused and combined together.
import jsxElem, { render } from "jsx-standalone";
function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
const CustomSeparator = props => (
<i>{[...Array(props.dots)].map(idx => ".")}</i>
);
function App() {
return (
<div>
<Hello name="foo" />
<CustomSeparator dots={50} />
<Hello name="bar" />
</div>
);
}
render(<App />, document.body);Fragments are supported as child elements everywhere, but are also supported as top-level JSX elements when using renderPrepend, render, and renderAppend.
function Hello() {
return <>
<h1>Hello</h1>
<h1>world</h1>
</>;
}
function App() {
return <Hello />;
}
render(<App />, document.body);It's possible add events listeners to components as functions using camelCase notation (e.g. onClick)
For example:
function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
function App() {
const clickHandler = function(e) {
alert("click function");
};
return (
<div>
<Hello onClick={() => alert("inline click function")} name="foo" />
<Hello onClick={clickHandler} name="bar" />
</div>
);
}function Hello(props) {
const names = props.names;
return (
<div>
{names.map(name => (
<h1>Hello {name}</h1>
))}
</div>
);
}
function App() {
return (
<div>
<Hello names={["foo", "bar"]} />
</div>
);
}function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
function App() {
return (
<div>
{document.location.hostname === "localhost" && (
<h1>Welcome to localhost</h1>
)}
<Hello name="foo" />
<Hello name="bar" />
</div>
);
}function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
const CustomSeparator = props => (
<i>{[...Array(props.dots)].map(idx => ".")}</i>
);
function App() {
return (
<div>
<Hello name="foo" />
<CustomSeparator dots={50} />
<Hello name="bar" />
{CustomSeparator({ dots: 10 })}
</div>
);
}Object can be passed to the style attribute with keys in camelCase.
import jsxElem, { render } from "jsx-standalone";
function Hello(props) {
return <h1>Hello {props.name}</h1>;
}
function App() {
return (
<div>
<Hello style={{ backgroundColor: "red" }} name="foo" />
<Hello style={{ backgroundColor: "blue", color: "white" }} name="bar" />
</div>
);
}
render(<App />, document.body);This package was originally developed by Terry Kerr and extended by Bodo Tasche.