React JSX Renderer
A React Component for Rendering JSX.
Description
React JSX Renderer is a React Component for rendering JSX to React nodes.
It has a JavaScript Runtime inside, and can execute the user's JSX with controlled behavior.
Features
- Rendering JSX as React nodes
- TypeScritpt ready
- Provides CommonJS and ES Modules
- JavaScript syntax and featues
- without async, await and generator
- Injectable custom React components
- Pass binding variables
- Applicable filters to parsed nodes
- You can create allowlist / denylist filters to tagName, attributes or properties
- Avoid user's call expressions
- Avoid user's new expressions
- Parse with meriyah
Installation
npm install -s react-jsx-renderer
(oryarn add react-jsx-renderer
)- Add
import { JSXRenderer } from 'react-jsx-renderer';
<JSXRenderer code="Hello, World" />
to renderHello, World
Requirements
- React: >= 16.0.0
Options
interface ParseOptions {
/**
* Options of parser
*/
meriyah?: meriyah.Options;
/**
* When this option is enabled, always parse as an expression.
*/
forceExpression?: boolean;
}
interface EvaluateOptions {
/**
* binding
*/
binding?: Binding;
/**
* components
*/
components?: ComponentsBinding;
/**
* Prefix of generated keys.
*/
keyPrefix?: string;
/**
* When this option is enabled, no key will be generated
*/
disableKeyGeneration?: boolean;
/**
* When this option is enabled, bindings will be excluded from the component search.
*/
disableSearchCompontsByBinding?: boolean;
/**
* When this option is enabled, Call Expression and New Expression will always return undefined.
*/
disableCall?: boolean;
/**
* When this option is enabled, New Expression will always return undefined.
*/
disableNew?: boolean;
/**
* When this option is enabled, access to undefined variables will raise an exception.
*/
raiseReferenceError?: boolean;
/**
* List of functions allowed to be executed.
*
* If empty, all functions will be allowed to execute.
*/
allowedFunctions?: AnyFunction[];
/**
* Add user-defined functions to the allowed list.
*/
allowUserDefinedFunction?: boolean;
/**
* List of functions denied to be executed.
*
* If empty, all functions will be allowed to execute.
*/
deniedFunctions?: AnyFunction[];
}
interface RenderingOptions {
/**
* List of filters to be applied to elements.
*/
elementFilters?: JSXElementFilter[];
/**
* List of filters to be applied to fragments.
*/
fragmentFilters?: JSXFragmentFilter[];
/**
* List of filters to be applied to text nodes.
*/
textFilters?: JSXTextFilter[];
/**
* When this option is enabled, non-existent HTML elements will not be rendered.
*/
disableUnknownHTMLElement?: boolean;
/**
* Function to determine Unknown HTML Element
*/
isUnknownHTMLElementTagName?: UnknownHTMLElementTagNameFunction;
}
interface RendererOptions extends {
/**
* JSX code
*/
code?: string;
/**
* The component that will be displayed instead when an error occurs.
*/
fallbackComponent?: JSXFallbackComponent;
/**
* If you want to receive the parsed result, set a Ref object to this option.
*/
refNodes?: Ref<JSXNode[]>;
}
Usage
Using like a simple HTML template engine
input:
import { render } from 'react-dom';
import { JSXRenderer } from 'react-jsx-renderer';
const root = document.getElementById('root');
render(
<JSXRenderer
binding={{ name: 'Sho Kusano' }}
code={'<p>Hello, {name}</p>'}
/>,
root
);
to:
<p>Hello, Sho Kusano</p>
Using JSX with JavaScript expressions
input:
render(
<JSXRenderer
binding={{
three: 3,
seven: 7,
}}
code={
'<p>+ {three + seven}</p>' +
'<p>- {three - seven}</p>' +
'<p>bitwise shift {three << seven}</p>'
}
/>,
root
);
to:
<p>+ 10</p>
<p>- -4</p>
<p>bitwise shift 384</p>
Using JSX with your favorite custom components
const Red = ({ children }) => <b style={{ color: 'red' }}>{children}</b>
render(
<JSXRenderer
components={{ RedColor: Red }}
code={'<p><RedColor>red</RedColor></p>'}
/>,
root
);
to:
<p><b style="color: red">red</b></p>
Convert JSX with filters
const hrefFilter = (element: JSXElement) => {
const { props, component, children } = element;
if (component !== 'a') return element;
let href = props.href || '';
if (href.includes('//')) {
href = secureURLConvert(href); // Add prefix https://secure.url/redirect?url=
}
const filteredProps = { ...props, href };
return { component, children, props: filteredProps };
}
render(
<JSXRenderer
elementFilters={[hrefFilter]}
code={
'<p><a href="/">root</a></p>' +
'<p><a href="../">upper directory</a></p>' +
'<p><a href="subdir">sub directory</a></p>' +
'<p><a href="https://github.com/">github</a></p>' +
}
/>,
root
);
to:
<p><a href="/">root</a></p>
<p><a href="../">upper directory</a></p>
<p><a href="subdir">sub directory</a></p>
<p><a href="https://secure.url/redirect?url=https://github.com">github</a></p>
Provide options by context
ex: Server side rendering.
import { JSDOM } from 'jsdom';
render(
<JSXRendererOptionsProvider isUnknownHTMLElement={(tagName) => {
const { window } = new JSDOM();
return window.document.createElement(tagName) instanceof window.HTMLUnknownElement;
}}>
<JSXRenderer
code={
'<p><unknown>Avoid</unknown></p>'
}
/>
</JSXRendererOptionsProvider>,
root
);
to:
<p></p>