Introducing JSX

The following code has a line of JSX:

function Title() {
  return <h1>This is a Title!</h1>
}

JSX is a special syntax for defining markup inside JavaScript. It resembles HTML, but it is not. It is in fact an XML dialect. When libraries that use compile, they pass JSX code to a function that converts it into virtual nodes. These are then used to compare with earlier renders to see if the DOM needs to be updated. Based on the differences, only the parts that changed will be updated. This results in very efficient code. Although their are various hyperscript functions that can be used to define markup in JavaScript, JSX is much more concise. As an advantage, JSX more closely resembles the markup that will be created.

Embedding Expressions in JSX

Because JSX is ultimately just JavaScript, you can embed JavaScript expressions in it. In the following example, 2 + 2, user.firstName, and formatName(user) are all valid expressions:

See the Pen Composi Tuts - JSX-1 by Robert Biggs (@rbiggs) on CodePen.

We split the JSX over multiple lines for readability. We also recommend wrapping JSX in parentheses to avoid the pitfalls of automatic semicolon insertion caused by new lines.

JSX is an Expression Too

After compilation, JSX expressions become regular JavaScript objects, or virtual dom objects that describe markup.

That means that you can include JSX inside of if statements and for loops, assign it to variables, accept it as an argument, and return it from functions:

See the Pen Composi Tuts - JSX-2 by Robert Biggs (@rbiggs) on CodePen.

Specifying Attributes with JSX

To specify string literals as attributes, use quotes:

const element = <div title="This is a DIV!" tabIndex="0"></div>

You can also embed a JavaScript expression between curly braces to create a value for an attribute. When you do so, remember not to use quotes around the JavaScript expression. Otherwise, the expression will get converted to a string and used as the attribute's value:

// Use a JavaScript expression for the image src value:
const element = <img src={user.avatarUrl} />

Unlike React, Preact and Inferno, which require attribute names to use camel case, with Composi you can use their normal HTML versions. In the following example, notice that all the attributes in the JSX resemble normal HTML attributes:

See the Pen Composi Tuts - JSX-3 by Robert Biggs (@rbiggs) on CodePen.

JSX Tags Can Have Children

A JSX tag can be single. In such a case it needs to be close with a forward slash:

const element = (
  <img title='My Avatar' src='avatar.png' />
)

You can also provide a JSX tag with children. When you do so, you insert the children between the parent tag's opening and closing, just like HTML:

const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
)

JSX Prevents Injection Attacks

JSX automatically encodes any potential script injection code. This helps prevent script injection attacks. It does this by converting all data to strings before rendering it to the DOM.

const title = function() {
  alert('This is a script!')
}
class Test extends Component {
  constructor(props) {
    super(props)
    this.root = 'header'
    this.render = (data) => 

{data}

} } const test = new Test() // When we pass the function title as data to the component, // nothing gets output. The component will not render: test.update(title)

In the case that the data contained markup, this too will be escaped:

See the Pen Composi Tuts - JSX-4 by Robert Biggs (@rbiggs) on CodePen.

JSX Represents Objects

When the JSX gets compiled, it is converted into an object that represents the nodes to be created:

function header() {
  return (
    <h1 class='heading' title='This is the header'>This is the Header!</h1>
  )
}
const result = header()
// result will equal:
{
  type: "h1", 
  props: {
    title: "This is the header!", 
    class: "header"
  }, 
  children: ["This is the Header!"]
}

innerHTML

By default any markup in data is escaped as a security precaution to help prevent cross-site scripting attacks. You can use the property innerHTML to inject data with markup into the document. This is highly risky. Hackers can use this to inject malicious code into the docuemnt. Use it only if you are absolutely sure you can trust the source of the data.

To use innerHTML just provide the data with the markup as the value for it. You could also use a function that returns the markup you want. Below is an example of how to use it:

function List({data}) {
  return (
    ul class="list">
      {
        data.map(item => <li innerHTML={item}></li>)
      }
    </ul>
  )
}
const items = [
'<div><strong>Whatever</strong></div>'
'<div><em>Something else</em></div>']

mount(<List data={items} />, 'section')

Because we are passing the data with markup directly to the list items through the property innerHTML, the markup will get converted into true DOM nodes. The result will look like this:

  • Whatever
  • Something else

In contrast, if we had just passed the data as normal, the markup would have been escaped:

function List({data}) {
  return (
    ul class="list">
      {
        data.map(item => <li>{item}</li>)
      }
    </ul>
  )
}
const items = [
'<div><strong>Whatever</strong></div>'
'<div><em>Something else</em></div>']

mount(<List data={items} />, 'section')

This would result in the following:

  • <div><strong>Whatever</strong></div>
  • <div><em>Something else</em></div>

Note: When using innerHTML on an element, it's best to always have that element not contain any other content. This will replace any other content already in the element.

 

s