JSX (JavaScript XML) is a JavaScript syntax extension that allows writing HTML-like code within JavaScript. JSX is needed to simplify creating and working with user interfaces in React and other libraries.
Main reasons for using JSX:
JSX is syntactic sugar for the React.createElement() function. It allows writing HTML-like code directly in JavaScript files, making user interface creation more intuitive and understandable.
// JSX code
const element = <h1 className="greeting">Hello, world!</h1>;
// Same in pure JavaScript
const element = React.createElement(
'h1',
{ className: 'greeting' },
'Hello, world!'
);
JSX was created to solve several key problems in user interface development:
Without JSX, creating even simple elements becomes cumbersome:
// Without JSX - cumbersome syntax
const element = React.createElement(
'div',
{ className: 'user-card' },
React.createElement('img', {
src: user.avatar,
alt: user.name,
className: 'avatar'
}),
React.createElement('h2', null, user.name),
React.createElement('p', null, user.email),
React.createElement(
'button',
{ onClick: handleDelete },
'Delete'
)
);
// With JSX - intuitive and clear syntax
const element = (
<div className="user-card">
<img src={user.avatar} alt={user.name} className="avatar" />
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={handleDelete}>Delete</button>
</div>
);
JSX makes component structure visually obvious:
// Hard to understand structure without JSX
function Navigation() {
return React.createElement(
'nav',
null,
React.createElement(
'ul',
null,
React.createElement('li', null,
React.createElement(Link, { to: '/' }, 'Home')
),
React.createElement('li', null,
React.createElement(Link, { to: '/about' }, 'About')
),
React.createElement('li', null,
React.createElement(Link, { to: '/contact' }, 'Contacts')
)
)
);
}
// With JSX structure is obvious at a glance
function Navigation() {
return (
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contacts</Link></li>
</ul>
</nav>
);
}
JSX allows easily embedding JavaScript expressions in HTML-like code:
function UserProfile({ user, isLoggedIn }) {
return (
<div className="profile">
<h1>User Profile</h1>
{isLoggedIn ? (
<div>
<img src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<p>Age: {user.age}</p>
<p>Email: {user.email}</p>
<button onClick={() => sendMessage(user.id)}>
Send Message
</button>
</div>
) : (
<p>Please log in</p>
)}
<footer>
Created: {new Date(user.createdAt).toLocaleDateString()}
</footer>
</div>
);
}
JSX is not valid JavaScript code and must be transpiled into regular JavaScript calls. This happens through Babel or other transpilers.
// Original JSX code
const element = (
<div className="container" id="main">
<h1>Header</h1>
<p>Paragraph with <strong>bold text</strong></p>
</div>
);
// After Babel transpilation
const element = React.createElement(
"div",
{ className: "container", id: "main" },
React.createElement("h1", null, "Header"),
React.createElement(
"p",
null,
"Paragraph with ",
React.createElement("strong", null, "bold text")
)
);
The React.createElement() function takes three parameters:
// React.createElement structure
React.createElement(
type, // 'div', 'h1', MyComponent
props, // { className: 'my-class', id: 'my-id' }
...children // child elements
)
// Examples
React.createElement('div', { className: 'container' });
React.createElement(MyComponent, { title: 'Hello' });
React.createElement('button', { onClick: handleClick }, 'Click me');
JSX is similar to HTML but has some differences:
// Basic syntax
const element = <h1>Hello, world!</h1>;
// Attributes (use camelCase)
const element = <img src="image.jpg" alt="Description" className="photo" />;
// Self-closing tags must be closed
const element = <br />; // correct
// const element = <br>; // error!
Curly braces {}
allow embedding JavaScript expressions:
const name = 'Alexander';
const age = 25;
const items = ['apple', 'banana', 'orange'];
function App() {
return (
<div>
{/* Embedding variables */}
<h1>Hello, {name}!</h1>
<p>Age: {age}</p>
{/* Embedding expressions */}
<p>In 5 years you will be {age + 5} years old</p>
{/* Embedding functions */}
<p>Random number: {Math.random()}</p>
{/* Embedding arrays */}
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
Some attributes in JSX differ from HTML:
// Differences from HTML
const element = (
<div>
{/* className instead of class */}
<div className="container">Container</div>
{/* htmlFor instead of for */}
<label htmlFor="name">Name:</label>
<input id="name" />
{/* onclick -> onClick (camelCase) */}
<button onClick={handleClick}>Click me</button>
{/* style takes an object */}
<div style={{
color: 'blue',
fontSize: '18px',
marginTop: '10px'
}}>
Styled text
</div>
</div>
);
JSX supports various conditional rendering approaches:
function Greeting({ isLoggedIn, user }) {
return (
<div>
{/* Ternary operator */}
<h1>{isLoggedIn ? 'Welcome!' : 'Please log in'}</h1>
{/* Logical AND */}
{isLoggedIn && <p>Hello, {user.name}!</p>}
{/* if-else with variables */}
{(() => {
if (isLoggedIn) {
return <Dashboard user={user} />;
} else {
return <LoginForm />;
}
})()}
{/* null to hide elements */}
{isLoggedIn ? <UserPanel /> : null}
</div>
);
}
JSX makes code more declarative and understandable:
// Imperative approach (without JSX)
function createTodoList(todos) {
const container = document.createElement('div');
container.className = 'todo-list';
todos.forEach(todo => {
const item = document.createElement('div');
item.className = 'todo-item';
item.textContent = todo.text;
if (todo.completed) {
item.style.textDecoration = 'line-through';
}
container.appendChild(item);
});
return container;
}
// Declarative approach (with JSX)
function TodoList({ todos }) {
return (
<div className="todo-list">
{todos.map(todo => (
<div
className="todo-item"
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
key={todo.id}
>
{todo.text}
</div>
))}
</div>
);
}
JSX allows detecting errors at compile time:
// Errors detected at compile time
const element = (
<div>
<h1>Header</h1>
{/* Error: unclosed tag */}
<p>Paragraph without closing tag
{/* Error: non-existent attribute */}
<button onClock={handleClick}>Click me</button>
</div>
);
JSX works excellently with TypeScript, providing strong typing:
interface User {
id: number;
name: string;
email: string;
}
interface UserCardProps {
user: User;
onDelete: (id: number) => void;
}
function UserCard({ user, onDelete }: UserCardProps) {
return (
<div className="user-card">
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={() => onDelete(user.id)}>Delete</button>
</div>
);
}
A component must return a single root element:
// ❌ Error: multiple root elements
function BadComponent() {
return (
<h1>Header</h1>
<p>Paragraph</p>
);
}
// ✅ Correct: single root element
function GoodComponent() {
return (
<div>
<h1>Header</h1>
<p>Paragraph</p>
</div>
);
}
// ✅ Alternative: React Fragment
function GoodComponent() {
return (
<>
<h1>Header</h1>
<p>Paragraph</p>
</>
);
}
When rendering lists, unique keys are required:
// ❌ Bad: missing keys
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li>{todo.text}</li> // Missing key
))}
</ul>
);
}
// ✅ Good: unique keys
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
// ❌ Errors
const element = (
<div class="container" onclick={handleClick}>
<input type="text" value={text}>
</div>
);
// ✅ Correct
const element = (
<div className="container" onClick={handleClick}>
<input type="text" value={text} />
</div>
);
While JSX is the standard in React, there are alternatives:
// Without JSX
function App() {
return React.createElement(
'div',
{ className: 'app' },
React.createElement('h1', null, 'Hello, world!'),
React.createElement('p', null, 'This app is without JSX')
);
}
import htm from 'htm';
import { h } from 'preact';
const html = htm.bind(h);
function App() {
return html`
<div class="app">
<h1>Hello, world!</h1>
<p>This app uses HTM</p>
</div>
`;
}
function h(tag, props, ...children) {
// Implementation of h function
}
function App() {
return h('div', { className: 'app' },
h('h1', null, 'Hello, world!'),
h('p', null, 'This app uses template literals')
);
}
JSX is recommended for the following cases:
// Great for complex components
function Dashboard({ user, stats, notifications }) {
return (
<div className="dashboard">
<header className="dashboard-header">
<h1>Dashboard</h1>
<UserMenu user={user} />
</header>
<main className="dashboard-content">
<StatsPanel stats={stats} />
<NotificationPanel notifications={notifications} />
<RecentActivity />
</main>
<footer className="dashboard-footer">
<p>© 2023 My Company</p>
</footer>
</div>
);
}
JSX is a powerful syntax extension that makes user interface development more intuitive and understandable:
✅ Main advantages:
✅ Key features:
✅ Best practices:
JSX has become the standard in React development and helps create more maintainable and understandable code for user interfaces.
Want more articles for interview preparation? Subscribe to EasyAdvice, bookmark the site, and improve yourself every day 💪