A guide to building interactive components using JSX.

Unlike HTML, which is a purely static markup language, JSX is full-fledged JavaScript:

export const heading = <h1>Hello, JSX!</h1>

This expression is neither HTML nor a string. It is a syntax extension to JavaScript, and it is a convenient way to describe a UI or a design. You can embed variable expressions by surrounding them with curly braces:

export const name = "Helen Kolska"
export const heading = <h1>Hello, {name}!</h1>

Functional components can be used to create new JSX elements, and encapsulate logic:

Hello, Janice Riesling! Today is Thursday.

<Greeting name="Janice Riesling" />

export const Greeting = ({ name }) => {
  const days = ["Sunday", "Monday", "Tuesday",
    "Wednesday", "Thursday", "Friday", "Saturday"]
  const dayName = days[new Date().getDay()]
  return <p>Hello, {name}! Today is {dayName}.</p>

It works for asynchronous functions:

Wait for it... ⏰
import { useEffect, useState } from "react"

export const StatusMessage = ({ delay }) => {
  const [ready, setReady] = useState(false)
  useEffect(() => {
    setTimeout(() => { setReady(true) }, delay * 1000)
  }, [])
  return <span>{ready ? "Ready! 🚀" : "Wait for it... ⏰"}</span>

<StatusMessage delay={5} />

Syntax differences with HTML

There are some important differences in how JSX should be authored, compared to HTML. Most notably:

  • Instead of class, className should be used.

  • style is not a string, but a JavaScript object. Instead of

    <div style="padding: 10; margin: 5" />

    the following syntax should be used

    <div style={{ padding: 10, margin: 5 }} />
  • Properties are camelCased (with the exception or aria-* properties, which remain hyphen-cased). Instead of

    <button onclick="myFunction()">Click me</button>

    the following syntax should be used

    <button onClick={myFunction}>Click me</button>

Authoring JSX in Motif

The declarative nature of JSX really shines when it's used within a document, where static content seamlessly mixes with dynamic JSX components.

Maths exercise

Two 🍰 is: 6.283185307179586!

# Maths exercise

Two 🍰 is: { pi * 2 }!

<CelebrateButton />

Read more about this in the MDX article.

Components from the web

JSX components can also be imported from the web, thanks to ES module support. Here is an example showing how to use the popular Tailwind UI library:

import { useState } from "react"
import { Switch } from "@headlessui/react"

export const Toggle = () => {
  const [enabled, setEnabled] = useState(false)
  return (
    <div className="p-20 rounded-md bg-gradient-to-r from-green-400 to-cyan-400 flex items-center justify-center">
      <div className="bg-teal-700 translate-x-9 hidden" />
          enabled ? "bg-teal-900" : "bg-teal-700"
        } relative inline-flex flex-shrink-0 h-[38px] w-[74px] border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75`}
            enabled ? "translate-x-9" : "translate-x-0"
          } pointer-events-none inline-block h-[34px] w-[34px] rounded-full bg-white shadow-lg transform ring-0 transition ease-in-out duration-200`}