JavaScript and React course Β· Module 1: React Basics

JSX syntax

6 min read
In this lesson5

JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write code resembling HTML directly in JavaScript. It is a declarative way of describing how the UI structure should look in React.

What exactly is JSX?

For a programmer who is just starting their adventure with React, JSX may seem strange - how is it possible that suddenly in the middle of JavaScript, HTML-like tags appear?

Imagine JSX as a translator between the JavaScript world and the HTML world. It allows you to describe UI structure in a way that is readable for humans (similar to HTML) while retaining all the power of JavaScript.

How does JSX work under the hood?

It's important to understand that browsers don't understand JSX natively. Before the code reaches the browser, it is compiled into regular JavaScript by tools like Babel.

For example, this JSX code:

1const element = <h1>Hello, world!</h1>;

Is transformed into:

1const element = React.createElement(
2  'h1',
3  null,
4  'Hello, world!'
5);

That is why older versions of React (up to 16) required importing React in every file with JSX. Since React 17, tools like Vite use the new JSX transform: the compiler imports the functions it needs from react/jsx-runtime itself, so import React from 'react' is no longer needed.

JSX rules

JSX may look like HTML, but it has several unique features and rules worth understanding:

1. Attribute names are in camelCase

Unlike HTML, where attributes are written in lowercase, in JSX many attributes are written in camelCase format:

1// HTML
2<div onclick="handleClick()" tabindex="0" class="container">
3
4// JSX
5<div onClick={handleClick} tabIndex={0} className="container">

Notice the differences:

  • onclick -> onClick
  • tabindex -> tabIndex
  • class -> className (because "class" is a reserved word in JavaScript)

2. Attribute values are JavaScript expressions

In JSX, attribute values are not always strings. You can use any JavaScript expression by enclosing them in curly braces:

1// Numeric value
2<input maxLength={10} />
3
4// Expression
5<img src={user.avatarUrl} />
6
7// Ternary operator (conditional operator)
8<div className={isActive ? 'active' : 'inactive'}>
9
10// Function
11<button onClick={handleClick}>

3. Self-closing tags must have a slash

In JSX, tags without children must have a closing slash:

1// HTML
2<input type="text">
3
4// JSX
5<input type="text" />

4. All tags must be closed

In HTML, some tags can remain unclosed (e.g., <img>, <br>), but in JSX all tags must be properly closed:

1// Invalid in JSX
2<img src="logo.png">
3
4// Valid in JSX
5<img src="logo.png" />

5. Element must be wrapped in a single parent element

JSX requires returning only one parent element. If you want to return multiple elements, you must wrap them in a container:

1// Invalid in JSX
2function Component() {
3  return (
4    <h1>Title</h1>
5    <p>Paragraph</p>
6  );
7}
8
9// Valid in JSX
10function Component() {
11  return (
12    <div>
13      <h1>Title</h1>
14      <p>Paragraph</p>
15    </div>
16  );
17}

If you don't want to introduce an additional DOM element, you can use a Fragment:

1function Component() {
2  return (
3    <>
4      <h1>Title</h1>
5      <p>Paragraph</p>
6    </>
7  );
8}

6. JavaScript in JSX

You can use JavaScript expressions in JSX by placing them in curly braces {}:

1function Greeting({ user }) {
2  return (
3    <div>
4      {/* Conditional expression */}
5      {user ? <h1>Welcome, {user.name}!</h1> : <h1>Welcome, stranger!</h1>}
6
7      {/* Performing calculations */}
8      <p>Your account was created {calculateDaysAgo(user.createdAt)} days ago</p>
9
10      {/* Mapping a list */}
11      <ul>
12        {user.hobbies.map(hobby => (
13          <li key={hobby.id}>{hobby.name}</li>
14        ))}
15      </ul>
16    </div>
17  );
18}

Advanced JSX techniques

Spread operators for props

You can use the spread operator (...) to pass all properties of an object as props:

1const buttonProps = {
2  type: 'submit',
3  disabled: false,
4  className: 'primary-button'
5};
6
7<button {...buttonProps}>Submit</button>

Dynamic attributes

You can dynamically determine element attributes:

1const inputType = isPassword ? 'password' : 'text';
2<input type={inputType} />

Conditional rendering

JSX offers several ways to conditionally render elements:

1// 1. Using the ternary operator
2{isLoggedIn ? <UserProfile /> : <LoginButton />}
3
4// 2. Using the logical && operator
5{isLoggedIn && <WelcomeMessage />}
6
7// 3. Using a variable
8let button;
9if (isLoggedIn) {
10  button = <LogoutButton />;
11} else {
12  button = <LoginButton />;
13}
14return <div>{button}</div>;

Inline styles

In JSX, inline styles are defined as JavaScript objects:

1const divStyle = {
2  color: 'blue',
3  backgroundColor: 'lightgray',
4  padding: '10px',
5  // Note that properties with hyphens (like background-color)
6  // are written in camelCase (backgroundColor)
7};
8
9<div style={divStyle}>Styled text</div>
10
11// Or directly in JSX
12<div style={{ fontWeight: 'bold', fontSize: '16px' }}>Bold text</div>

Comments in JSX

Comments in JSX are placed inside curly braces and use JavaScript comment syntax:

1<div>
2  {/* This is a comment in JSX */}
3  <h1>Title</h1>
4  {/*
5    You can also use
6    multiline comments
7  */}
8</div>

Common JSX pitfalls

1. Rendering boolean values

JSX does not render boolean values, null, and undefined:

1// These expressions render nothing on screen
2<div>{true}</div>
3<div>{false}</div>
4<div>{null}</div>
5<div>{undefined}</div>
6
7// But numbers and strings are rendered
8<div>{0}</div>
9<div>{"string"}</div>

2. Confusing quotes and curly braces

Remember that quotes are used for string values and curly braces for JavaScript expressions:

1// Correct
2<input type="text" maxLength={10} />
3
4// Incorrect
5<input type={text} maxLength="10" /> // error: 'text' is not defined

3. Attempting to use if/else directly in JSX

You cannot use if/else statements directly in JSX because JSX is an expression, not a statement:

1// Incorrect
2<div>
3  {if (isLoggedIn) {
4    return <UserProfile />;
5  } else {
6    return <LoginButton />;
7  }}
8</div>
9
10// Correct - use the ternary operator
11<div>
12  {isLoggedIn ? <UserProfile /> : <LoginButton />}
13</div>

Summary

JSX is one of the most important aspects of React, which greatly simplifies creating user interfaces. Thanks to JSX, you can:

  • Write UI structure in a way resembling HTML
  • Combine markup with JavaScript logic
  • Create components that are readable and easy to maintain
  • Leverage the full power of JavaScript for dynamic content rendering

Remember that JSX is just syntax that is transformed into plain function calls: React.createElement() or, with the new transform, jsx() from react/jsx-runtime. Understanding the rules and capabilities of JSX is key to effective programming in React.

Code for this lesson: App.jsx
1import React, { useState } from 'react';
2
3// Demonstration of various JSX aspects
4export default function App() {
5  const [count, setCount] = useState(0);
6  const [showAdvanced, setShowAdvanced] = useState(false);
7
8  // Variables used in JSX
9  const userName = "Cosmic Explorer";
10  const currentDate = new Date().toLocaleDateString('en-US');
11  const items = ['Galaxy Map', 'Quantum Compass', 'Life Scanner'];
12  const isLoggedIn = true;
13
14  // Style as a JavaScript object
15  const headerStyle = {
16    background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
17    padding: '30px',
18    borderRadius: '16px',
19    color: 'white',
20    textAlign: 'center',
21    marginBottom: '30px'
22  };
23
24  return (
25    <div style={{
26      fontFamily: 'Arial, sans-serif',
27      maxWidth: '900px',
28      margin: '0 auto',
29      padding: '20px',
30      backgroundColor: '#0a0a1a',
31      minHeight: '100vh',
32      color: 'white'
33    }}>
34      {/* Comment in JSX */}
35      <header style={headerStyle}>
36        <h1 style={{ margin: 0 }}>JSX in Action</h1>
37        <p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>
38          Learn JSX syntax - the heart of React
39        </p>
40      </header>
41
42      {/* JavaScript expressions in JSX */}
43      <section style={{
44        backgroundColor: '#1a1a2e',
45        padding: '25px',
46        borderRadius: '12px',
47        marginBottom: '20px'
48      }}>
49        <h2 style={{ color: '#00d4ff', marginTop: 0 }}>
50          JavaScript Expressions in JSX
51        </h2>
52        <div style={{ display: 'grid', gap: '15px' }}>
53          <div style={{ padding: '15px', backgroundColor: '#252545', borderRadius: '8px' }}>
54            <code style={{ color: '#888' }}>{'{'} userName {'}'}</code>
55            <p style={{ margin: '10px 0 0 0' }}>Result: <strong>{userName}</strong></p>
56          </div>
57          <div style={{ padding: '15px', backgroundColor: '#252545', borderRadius: '8px' }}>
58            <code style={{ color: '#888' }}>{'{'} 2 + 2 {'}'}</code>
59            <p style={{ margin: '10px 0 0 0' }}>Result: <strong>{2 + 2}</strong></p>
60          </div>
61          <div style={{ padding: '15px', backgroundColor: '#252545', borderRadius: '8px' }}>
62            <code style={{ color: '#888' }}>{'{'} currentDate {'}'}</code>
63            <p style={{ margin: '10px 0 0 0' }}>Result: <strong>{currentDate}</strong></p>
64          </div>
65        </div>
66      </section>
67
68      {/* Conditional rendering */}
69      <section style={{
70        backgroundColor: '#1a1a2e',
71        padding: '25px',
72        borderRadius: '12px',
73        marginBottom: '20px'
74      }}>
75        <h2 style={{ color: '#00d4ff', marginTop: 0 }}>
76          Conditional Rendering
77        </h2>
78
79        {/* Operator && */}
80        {isLoggedIn && (
81          <div style={{
82            padding: '15px',
83            backgroundColor: '#4caf50',
84            borderRadius: '8px',
85            marginBottom: '15px'
86          }}>
87            You are logged in as: {userName}
88          </div>
89        )}
90
91        {/* Ternary operator */}
92        <div style={{
93          padding: '15px',
94          backgroundColor: count > 5 ? '#ff9800' : '#2196f3',
95          borderRadius: '8px'
96        }}>
97          {count > 5 ? 'Counter is high!' : 'Counter is low'}
98          <div style={{ marginTop: '10px' }}>
99            <button
100              onClick={() => setCount(count + 1)}
101              style={{
102                padding: '8px 16px',
103                marginRight: '10px',
104                backgroundColor: '#4caf50',
105                color: 'white',
106                border: 'none',
107                borderRadius: '4px',
108                cursor: 'pointer'
109              }}
110            >
111              +1 (now: {count})
112            </button>
113            <button
114              onClick={() => setCount(0)}
115              style={{
116                padding: '8px 16px',
117                backgroundColor: '#f44336',
118                color: 'white',
119                border: 'none',
120                borderRadius: '4px',
121                cursor: 'pointer'
122              }}
123            >
124              Reset
125            </button>
126          </div>
127        </div>
128      </section>
129
130      {/* Rendering lists */}
131      <section style={{
132        backgroundColor: '#1a1a2e',
133        padding: '25px',
134        borderRadius: '12px',
135        marginBottom: '20px'
136      }}>
137        <h2 style={{ color: '#00d4ff', marginTop: 0 }}>
138          Rendering Lists with .map()
139        </h2>
140        <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
141          {items.map((item, index) => (
142            <li key={index} style={{
143              padding: '12px 15px',
144              backgroundColor: '#252545',
145              borderRadius: '8px',
146              marginBottom: '10px',
147              display: 'flex',
148              alignItems: 'center',
149              gap: '10px'
150            }}>
151              <span style={{
152                width: '30px',
153                height: '30px',
154                backgroundColor: '#667eea',
155                borderRadius: '50%',
156                display: 'flex',
157                alignItems: 'center',
158                justifyContent: 'center',
159                fontWeight: 'bold'
160              }}>
161                {index + 1}
162              </span>
163              {item}
164            </li>
165          ))}
166        </ul>
167      </section>
168
169      {/* Show/hide advanced */}
170      <button
171        onClick={() => setShowAdvanced(!showAdvanced)}
172        style={{
173          width: '100%',
174          padding: '15px',
175          backgroundColor: '#667eea',
176          color: 'white',
177          border: 'none',
178          borderRadius: '8px',
179          cursor: 'pointer',
180          fontSize: '16px',
181          fontWeight: 'bold'
182        }}
183      >
184        {showAdvanced ? 'Hide' : 'Show'} advanced examples
185      </button>
186
187      {showAdvanced && (
188        <section style={{
189          backgroundColor: '#1a1a2e',
190          padding: '25px',
191          borderRadius: '12px',
192          marginTop: '20px'
193        }}>
194          <h2 style={{ color: '#ff9800', marginTop: 0 }}>
195            Advanced JSX
196          </h2>
197          <div style={{
198            backgroundColor: '#252545',
199            padding: '15px',
200            borderRadius: '8px',
201            fontFamily: 'monospace',
202            fontSize: '14px',
203            lineHeight: '1.6'
204          }}>
205            <div style={{ color: '#888' }}>// Fragment - grouping without extra DOM</div>
206            <div style={{ color: '#61dafb' }}>{'<>'}</div>
207            <div style={{ color: '#ce9178', paddingLeft: '20px' }}>{'  <Element1 />'}</div>
208            <div style={{ color: '#ce9178', paddingLeft: '20px' }}>{'  <Element2 />'}</div>
209            <div style={{ color: '#61dafb' }}>{'</>'}</div>
210          </div>
211        </section>
212      )}
213    </div>
214  );
215}

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What is one of the key rules of JSX syntax?

Hands-on tasks in the game

  • Horizontal ordering

    Arrange the correct JSX element syntax from left to right:

  • Code editor

    Create a ControlPanel with: an h1 heading 'Control Panel', a <ul> list of 3 systems (using map), and a button 'Activate' with onClick. Use className for styling.

  • Code editor

    Without JSX: inside the App component, use React.createElement to create an element of the SpaceshipPart component with the name and type properties (e.g. name: 'Engine', type: 'propulsion') and return it. SpaceshipPart itself should display the part's name and type.

  • Click in order

    Build a correct JavaScript expression embedded in a JSX element:

  • Horizontal ordering

    Arrange the React.createElement syntax to create an h1 element with text:

  • Horizontal ordering

    Arrange the syntax for rendering the App component to the DOM in main.jsx (React 18+):

  • Code editor

    Create a CrewMembers component that returns several elements (e.g. an <li> for each crew member) grouped in a Fragment (<></> or <React.Fragment>) instead of an extra <div>.

  • Vertical ordering

    Arrange the process of JSX compilation to the DOM:

  • Code editor

    Wrap the main App component in React.StrictMode to enable additional checks during development.

  • Horizontal ordering

    Arrange the correct import syntax for the ReactDOM library for browser rendering:

  • Code editor

    Use ReactDOM.createRoot to render the SpaceStation component into the DOM element with id 'space-station' (just like in main.jsx from the Vite lesson).

  • Code editor

    Create a SystemStatus component that accepts props: {name, status, power}. Display: the system name, status (online/offline), and power consumption.

  • Horizontal ordering

    Arrange the correct import syntax for the React library:

Useful articles