What is JSX and why is it needed?

👨‍💻 Frontend Developer 🟠 May come up 🎚️ Easy
#React

Brief Answer

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:

  • Simplifies writing declarative UI code
  • Improves readability and understandability of components
  • Allows using JavaScript power within HTML-like syntax
  • Provides static typing and compile-time error checking

What is 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.

Key JSX Characteristics

  1. HTML-like syntax — resembles regular HTML
  2. JavaScript integration — allows embedding JavaScript expressions
  3. Compiles to JavaScript — transforms into regular JavaScript calls
  4. Static checking — errors detected at compile time
// JSX code
const element = <h1 className="greeting">Hello, world!</h1>;
 
// Same in pure JavaScript
const element = React.createElement(
  'h1',
  { className: 'greeting' },
  'Hello, world!'
);

Why JSX is Needed

JSX was created to solve several key problems in user interface development:

1. Simplifying UI Creation

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>
);

2. Improving Code Readability

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>
  );
}

3. JavaScript and HTML Integration

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>
  );
}

How JSX Works

JSX is not valid JavaScript code and must be transpiled into regular JavaScript calls. This happens through Babel or other transpilers.

Transpilation Process

// 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")
  )
);

React.createElement Structure

The React.createElement() function takes three parameters:

  1. type — element type (string or component)
  2. props — element properties (attributes)
  3. children — child elements
// 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 Syntax

1. Basic Elements

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!

2. Embedding JavaScript Expressions

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>
  );
}

3. Attributes in JSX

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>
);

4. Conditional Rendering

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 Advantages

1. Declarativeness

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>
  );
}

2. Static Error Checking

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>
);

3. TypeScript Integration

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>
  );
}

Common Mistakes and Best Practices

1. Returning a Single Root Element

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>
    </>
  );
}

2. Using Keys in Lists

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>
  );
}

3. Proper Attribute Usage

// ❌ 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>
);

JSX Alternatives

While JSX is the standard in React, there are alternatives:

1. Pure JavaScript

// 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')
  );
}

2. HTM (Hyperscript Tagged Markup)

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>
  `;
}

3. Template literals

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')
  );
}

When to Use JSX

JSX is recommended for the following cases:

  1. React applications — standard for all React projects
  2. Components with complex markup — improves readability
  3. Team development — facilitates collaboration
  4. TypeScript projects — provides strong typing
// 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>&copy; 2023 My Company</p>
      </footer>
    </div>
  );
}

Summary

JSX is a powerful syntax extension that makes user interface development more intuitive and understandable:

Main advantages:

  • Simplifies UI component creation
  • Improves code readability
  • Integrates JavaScript and HTML-like syntax
  • Provides static error checking

Key features:

  • Compiles to React.createElement() calls
  • Supports embedding JavaScript expressions
  • Requires transpilation to work in browsers
  • Works excellently with TypeScript

Best practices:

  • Use unique keys in lists
  • Return a single root element
  • Follow attribute naming conventions
  • Use fragments for grouping elements

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 💪