61

Can I use inline HTML in a script as below by using a library like jsx:

<script src="jsx-transform.js"></script>
<script type="text/jsx">
define('component', function () {
   return (<div>test html code</div>);
});
</script>
double-beep
  • 5,031
  • 17
  • 33
  • 41
SKing7
  • 2,204
  • 4
  • 21
  • 29

8 Answers8

32

I was able to write JSX files and inject them into an HTML page using a 'fake' React file.

no-react.js

/**
 * Include this script in your HTML to use JSX compiled code without React.
 */

const React = {
    createElement: function (tag, attrs, children) {
        var element = document.createElement(tag);

        for (let name in attrs) {
            if (name && attrs.hasOwnProperty(name)) {
                let value = attrs[name];
                if (value === true) {
                    element.setAttribute(name, name);
                } else if (value !== false && value != null) {
                    element.setAttribute(name, value.toString());
                }
            }
        }
        for (let i = 2; i < arguments.length; i++) {
            let child = arguments[i];
            element.appendChild(
                child.nodeType == null ?
                    document.createTextNode(child.toString()) : child);
        }
        return element;
    }
};

Then compile your jsx.

test.jsx

const title = "Hello World";
document.getElementById('app').appendChild(
    <div>
        <h1>{title}</h1>
        <h2>This is a template written in TSX, then compiled to JSX by tsc (the Typescript compiler), and finally
            injected into a web page using a script</h2>
    </div>
);

Resulting compiled 'test.js'

var title = "Hello World";
document.querySelector('#app').appendChild(React.createElement("div", null,
    React.createElement("h1", null, title),
    React.createElement("h2", null, "This is a template written in TSX, then compiled to JSX by tsc (the Typescript compiler), and finally" + " " + "injected into a web page")));

And finally, the HTML page that includes both scripts.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>no-react</title>
    <script src="no-react.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>

<script src="test.js"></script>
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
27

React renders JSX html syntax to JS using functions such as React.createElement (among others for Fragments and so on). But that all boils down to the @babel/plugin-transform-react-jsx plugin which does the transpiling of this:

return(<div id="hello">Hello World</div>)

into this...

return React.createElement('div', {id: 'hello'}, 'Hello World');

However you can replace React.createElement with you're own function to do this. You can read more on that here: https://babeljs.io/docs/en/next/babel-plugin-transform-react-jsx.html

You should also look at libraries which do exactly this such as nervjs, jsx-render and deku. All of these use a JSX html syntax without react. Some (such as jsx-render) are only focused on converting JSX to the final JS, which might be what you're looking for.

The author of that package wrote an article on it here: https://itnext.io/lessons-learned-using-jsx-without-react-bbddb6c28561

Also Typescript can do this if you use that...but I've no first hand experience with it.

To sum up

You can do it without React, but not without Babel or Typescript.

zzxoto
  • 62
  • 6
Luke Watts
  • 601
  • 7
  • 15
  • 2
    This is the correct answer and deserves all the upvotes. – superluminary Dec 16 '19 at 20:39
  • You're correct about the transpilation part, but it doesn't have to be done externally. Although it's uncommon it's still possible to [run babeljs right in the the browser](https://reactjs.org/docs/add-react-to-a-website.html) – ruX Feb 02 '22 at 16:49
11

JSX is not a string-based templating language; it compiles to actual JavaScript function calls. For example,

<div attr1="something" attr2="other">
  Here are some <span>children</span>
</div>

transpiles to

React.createElement("div", {attr1: "something", attr2: "other"}, 
  "Here are some ", React.createElement("span", null, "children")
)
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • thanks, but it need React.there is a single library like jsx to do this? – SKing7 May 25 '15 at 04:54
  • @SKing7 To do what? Your question doesn't make sense. JSX turns XML-looking syntax into JavaScript function calls. What do you actually want it to do? – Michelle Tilley May 25 '15 at 04:59
  • The are separate virtual DOM libraries, like [this one](https://github.com/Matt-Esch/virtual-dom). – Michelle Tilley May 25 '15 at 05:00
  • i want to write html in js codes in my project ,but without React – SKing7 May 25 '15 at 09:16
  • 3
    @SKing7 Does using strings work for you? `return ("
    test html code
    ");` If not, why not? Maybe that will help narrow down what you're trying to do.
    – Michelle Tilley May 25 '15 at 16:32
  • 1
    @SKing7 If you're using an ES6 transpiler (such as the one that ships with the JSX Transformer), you can use template strings (with backticks) which support multiple lines. See this example: http://jsfiddle.net/BinaryMuse/hovssy49/ – Michelle Tilley May 26 '15 at 04:14
  • thanks,i should parse the template string to normal string,because browser dont support the template string well; – SKing7 May 26 '15 at 06:26
  • I think @MichelleTilley has the right answer here. If you just want to inline HTML, you don't need JSX. Multi-line template strings should meet the need for any fancy libraries or runtime complexity. – Robert Levy Nov 30 '15 at 16:46
  • @RobertLevy Using template strings wont give you stuff like auto formatting, intellisense, inspection and various tooling though. – Alex Mar 04 '16 at 09:26
6

I was looking for something like this myself. A way to write Components and JSX like for simple projects. Didn't find one that I liked so I've built this: https://github.com/SagiMedina/Aviya#aviya Have a look, maybe it will answer your problem as well.

Sagi Medina
  • 915
  • 1
  • 9
  • 11
4

It looks like the dom-chef package can do this. From the readme:

  • No API, JSX gets auto transformed into actual DOM elements.

// babel.config.js

const plugins = [
  [
    '@babel/plugin-transform-react-jsx',
    {
      pragma: 'h',
      pragmaFrag: 'DocumentFragment',
    }
  ]
];

// ...

const {h} = require('dom-chef');

const handleClick = e => {
    // <a> was clicked
};

const el = (
    <div class="header">
        <a href="#" class="link" onClick={handleClick}>Download</a>
    </div>
);

document.body.appendChild(el);
jtbandes
  • 115,675
  • 35
  • 233
  • 266
3

You will need something to transform the JSX into JS function calls. React uses Babel to do this -- you would probably be best off with that too.

There's a library by the creators of Preact that essentially does what you're after called vhtml. The tagline is "Render JSX/Hyperscript to HTML strings, without VDOM".

Here is a copy of the Readme at time of writing:

Usage

// import the library:
import h from 'vhtml';

// tell babel to transpile JSX to h() calls:
/** @jsx h */

// now render JSX to an HTML string!
let items = ['one', 'two', 'three'];

document.body.innerHTML = (
  <div class="foo">
    <h1>Hi!</h1>
    <p>Here is a list of {items.length} items:</p>
    <ul>
      { items.map( item => (
        <li>{ item }</li>
      )) }
    </ul>
  </div>
);

New: "Sortof" Components!

vhtml intentionally does not transform JSX to a Virtual DOM, instead serializing it directly to HTML. However, it's still possible to make use of basic Pure Functional Components as a sort of "template partial".

When vhtml is given a Function as the JSX tag name, it will invoke that function and pass it { children, ...props }. This is the same signature as a Pure Functional Component in react/preact, except children is an Array of already-serialized HTML strings.

This actually means it's possible to build compositional template modifiers with these simple Components, or even higher-order components.

Here's a more complex version of the previous example that uses a component to encapsulate iteration items:

let items = ['one', 'two'];

const Item = ({ item, index, children }) => (
  <li id={index}>
    <h4>{item}</h4>
    {children}
  </li>
);

console.log(
  <div class="foo">
    <h1>Hi!</h1>
    <ul>
      { items.map( (item, index) => (
        <Item {...{ item, index }}>
          This is item {item}!
        </Item>
      )) }
    </ul>
  </div>
);

The above outputs the following HTML:

<div class="foo">
  <h1>Hi!</h1>
  <ul>
    <li id="0">
      <h4>one</h4>This is item one!
    </li>
    <li id="1">
      <h4>two</h4>This is item two!
    </li>
  </ul>
</div>
Julian Suggate
  • 627
  • 1
  • 6
  • 14
1

You can have a look at documentation: in-browser JSX transform, and also see Babel documentation

You can achieve what you want, but it is discouraged in production...

Mike Aski
  • 9,180
  • 4
  • 46
  • 63
0

Jsx parse the return (<div>test html code</div>); to something like this return React.createElement('div', {...});

then if you don't using react.js, then browser will not know what React is and trigger an error.

Chenglu
  • 1,757
  • 2
  • 14
  • 23
  • you can only use react.js without jsx but not the other way around, jsx is just a syntax sugar for react. – Chenglu May 25 '15 at 04:44
  • thanks, is there a single library like jsx to do this? – SKing7 May 25 '15 at 04:55
  • do you mean jsx compiler? if you do then yes, react has a tools that can do the thing, `npm install -g react-tools` this will give you a jsx binary, you can get more information at https://facebook.github.io/react/downloads.html – Chenglu May 25 '15 at 05:09
  • 1
    @louisthebang i beg to differ. JSX is just syntastic sugar for hyperscript. – lohfu Feb 23 '17 at 12:00