Skip to main content

JSX

JSX Rules and Gotchas

Written by Published

Nearly every JSX error message is one of five mistakes. Recognising them by their error text saves more time than memorising the rules.

Returning nothing by accident

This is the most confusing one, because there is no error - the component simply renders nothing. It happens when a return is followed by a line break before the JSX.

The semicolon that eats your UI

jsx

function Broken() {
  // JavaScript inserts a semicolon after return, so this returns undefined.
  return
  ;<h3>You will never see this</h3>
}

function Fixed() {
  // Opening a bracket on the same line as return avoids it entirely.
  return (
    <h3>This one renders</h3>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
  <div>
    <Broken />
    <Fixed />
  </div>
)

Automatic semicolon insertion ends the statement at the line break. Always put an opening parenthesis on the same line as return and the problem cannot occur.

Rendering an object

React refuses to render a plain object and throws Objects are not valid as a React child. It is telling you it has no way to turn { name: "Ada" } into text - you have to choose.

Reach for the value you meant

jsx

function Fixed() {
  const user = { name: "Ada", visits: 3 }

  return (
    <div>
      {/* <p>{user}</p> would throw. Pick a field: */}
      <p>{user.name}</p>
      {/* Or stringify it deliberately, useful while debugging: */}
      <pre>{JSON.stringify(user, null, 2)}</pre>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Fixed />)

The rest of the list

  1. Two root elements - Adjacent JSX elements must be wrapped. Use a fragment.
  2. An unclosed tag - <img> or
    without the slash. The error points at the next tag, not the real culprit.
  3. class instead of className - React warns in the console and the styling silently does not apply.
  4. A statement in braces - Unexpected token from an if or for. Move it above the return.
  5. A lowercase component - no error at all; the browser looks for an unknown HTML element and renders nothing.

Reading the error

Babel reports the line where parsing failed, which is usually one line after the mistake. If line 12 looks fine, the missing bracket or slash is on line 11.

Try it: delete a closing tag in any example on this page and press Run. The message tells you exactly which token it did not expect.