JavaScript and React course Β· Module 1: React Basics
JSX syntax
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->onClicktabindex->tabIndexclass->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 defined3. 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. 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: