https://github.com/exogen/react-dynamic-html
dangerouslySetInnerHTML but with slots for React components!
https://github.com/exogen/react-dynamic-html
cms dynamic html react template
Last synced: 9 months ago
JSON representation
dangerouslySetInnerHTML but with slots for React components!
- Host: GitHub
- URL: https://github.com/exogen/react-dynamic-html
- Owner: exogen
- License: mit
- Created: 2018-12-20T06:17:38.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2018-12-23T04:13:30.000Z (about 7 years ago)
- Last Synced: 2025-04-03T11:15:42.413Z (9 months ago)
- Topics: cms, dynamic, html, react, template
- Language: JavaScript
- Homepage: https://exogen.github.io/react-dynamic-html/
- Size: 705 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# react-dynamic-html
Like `dangerouslySetInnerHTML` but with simple old-school template substitution,
where values can be React elements.
Because sometimes you just need to work with HTML from an older system or CMS.
👉 **[Demo!](https://exogen.github.io/react-dynamic-html/)** 👈
- Tiny 1KB client-side bundle, no dependencies necessary
- Template values can be dynamic React components
- Universal, supports server side rendering (SSR)
- Components get the correct context from above
- Template updates even preserve component state!
- 100% test coverage
## Example
```js
import Template from "react-dynamic-html";
/**
* This app shows off rendering interactive React components and
* dynamic values into an HTML string.
*/
class App extends React.Component {
state = {
name: "Alice"
};
toggleName = () => {
this.setState(state => ({
name: state.name === "Alice" ? "Bob" : "Alice"
}));
};
render() {
return (
Hey, {name}!
Click here: {button}
`}
values={{
name: this.state.name,
button: Toggle
}}
/>
);
}
}
```
## API
### Template
#### Props
Name
Type
Default
Description
string
String
The template HTML string.
values
Object
{}
An object mapping variable names (used in the template string) to their
values. React element values will be rendered into a placeholder node.
valueTags
Object of…
  String
{}
The DOM element type in which to render specific React elements that
appear in `values`. Only React elements are wrapped.
defaultValueTag
String
span
The DOM element type in which to render React element values by default.
To override the tag for individual values, use `valueTags`.
escapeValues
Boolean
true
Whether or not to escape values inserted into the HTML.
valuePattern
One of…
  String
  Object
/(\{([$\w]+)\})/g
The string or RegExp that specifies the variable substitution syntax.
Each instance will be replaced. The second capture group should be the
name of the variable. String values will be passed to RegExp with the
`g` flag.
as
String
div
The DOM element type in which to render the entire template.
## Motivation
As described in the introduction, sometimes you need to deal with HTML coming
from another system, often controlled by non-technical colleagues. This usually
isn’t a problem (just use `dangerouslySetInnerHTML`) – until they request the
ability to add call-to-action buttons (or other interactive elements) that
ultimately need to call out to your React app. Unless you’re fine with falling
back to vanilla JavaScript for this behavior (i.e. doing `querySelector`,
`addEventListener`, etc. in your lifecycle hooks), now you’ve got a nontrivial
problem on your hands!
Consider the [FormattedMessage](https://github.com/yahoo/react-intl/wiki/Components#formattedmessage)
and [FormattedHTMLMessage](https://github.com/yahoo/react-intl/wiki/Components#formattedhtmlmessage)
components from [react-intl](https://github.com/yahoo/react-intl).
FormattedMessage values can include React elements:
> `` also supports rich-text formatting by passing React
> elements to the `values` prop.
On the other hand, FormattedHTMLMessage comes with a disclaimer:
> … the resulting formatted message will be set via `dangerouslySetInnerHTML`.
> This means that values cannot contain React elements like ``
> and this component will be less performant.
Using this library, you could make FormattedHTMLMessage work with React
elements too!
You might think it’s easy to translate HTML into `React.createElement` calls
in the browser – either by parsing it yourself or injecting it and crawling
the resulting DOM. There are a handful of libraries that already do this, but
it requires a nontrivial amount of code: remember that React requires using
different names for many attributes, and has special handling for others (like
`style`, where you’d have to parse a string of rules into an object). That
approach is both slow and will bloat your bundle size.
## Other Solutions
This library should pretty much be a last resort. Here’s some advice:
**If you can preprocess the HTML** into a simple AST and serve that to your app
instead, do that. Then you can easily translate nodes into `React.createElement`
calls. Everything will be easier and React will be happy. (This library does
exactly that during server-side rendering in order to render with the correct
context, but doing this client-side requires large dependencies.)
**If your HTML authors are technical** and are editing raw HTML, you will still
need to do most of what this library does, but you can skip the step where
`{placeholder}` syntax is parsed. Instead, you can come up with some fancy
`data-` attributes to indicate how to transform certain elements into React
components (even allowing them to pass simple props). The remaining
complications (like not simply being able to use `ReactDOM.render` or
`renderToString` on the resulting elements due to context) will unfortunately be
the same.
**If the HTML comes from a WYSIWYG editor** where special `{placeholder}`
syntax is more accessible, and you just need to stick React components (like
interactive buttons) and text in a few places, use this library.