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-standalone
You'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-env
and 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.