JSX: The Syntax That Powers Modern React Development

Master JSX fundamentals, expressions, and best practices for building efficient, maintainable React applications

JSX stands as the cornerstone syntax that makes React development both powerful and intuitive. Rather than separating your markup into HTML files and your logic into JavaScript files, JSX allows you to write HTML-like syntax directly within your JavaScript code. This approach might seem unusual at first--after all, we've spent years being told that separation of concerns means keeping HTML and JavaScript separate. But JSX fundamentally reimagines what component-based development looks like, enabling you to express your UI's structure, behavior, and styling in a single, cohesive syntax that compiles down to efficient JavaScript.

At its core, JSX is a syntax extension for JavaScript that lets you describe what your UI should look like using familiar HTML-like syntax. When you write <h1>Hello, World!</h1> in your React component, you're not actually writing HTML--you're writing JSX that gets compiled into JavaScript function calls. This compilation happens during your build process, transforming declarative markup into the React.createElement() calls that actually render content to the DOM. The beauty of this approach lies in its simplicity: you get the readability and familiarity of HTML syntax while maintaining the full power of JavaScript for logic, conditionals, and dynamic behavior.

Understanding JSX deeply is essential because it affects everything from how you structure your components to how you optimize your application's performance. The choices you make in JSX directly impact how React reconciles changes and updates the DOM, making JSX knowledge fundamental to writing efficient, maintainable React applications. This guide covers everything from basic syntax to advanced patterns, ensuring you can leverage JSX's full potential in your projects. Pair this knowledge with our guide to React components, React state management, and React props to build complete, production-ready applications.

What You'll Learn in This Guide

Comprehensive coverage of JSX from fundamentals to advanced patterns

JSX Fundamentals

Understand the core syntax, how it differs from HTML, and why it matters for your React applications.

Expressions & Interpolation

Master the curly brace syntax for embedding dynamic JavaScript values directly in your markup.

Component Composition

Learn best practices for structuring components, using fragments, and organizing complex JSX trees.

Performance Optimization

Discover techniques for writing efficient JSX that minimizes unnecessary re-renders and DOM updates.

What Makes JSX Different From HTML

While JSX shares visual similarities with HTML, several key differences make it a more powerful--and sometimes challenging--syntax to master. Understanding these differences prevents common mistakes and helps you write more effective React components. The strictness of JSX catches potential errors early and enforces better coding practices, ultimately leading to more robust applications.

Tag Closing Requirements

In HTML, certain elements like <br> and <img> can technically exist without explicit closing tags, though valid HTML technically requires self-closing syntax. JSX, however, is strictly XML-based, meaning every tag must be properly closed. Self-closing tags like <img /> and <br /> must include the forward slash, and standard tags like <div> require matching closing tags. This requirement isn't merely syntactic--it reflects how the React compiler interprets your markup into where every element must have a clear definition JavaScript objects, of its structure.

// Correct self-closing tags
<img src="logo.png" alt="Logo" />
<br />
<input type="text" />

// WRONG - missing closing slash
<img src="logo.png">

CamelCase Attributes

HTML attributes in JSX use camelCase naming instead of kebab-case. The most commonly encountered example is className instead of class, since class is a reserved word in JavaScript. Similarly, you'll write onClick instead of onclick, tabIndex instead of tabindex, and maxLength instead of maxlength. This convention extends to all compound attribute names, following JavaScript's established naming conventions and ensuring that your JSX compiles cleanly without requiring quotes around attribute names.

// JSX uses camelCase
<button onClick={handleClick} tabIndex={0} className="btn-primary">
 Click Me
</button>

// HTML uses kebab-case (not JSX)
<button onclick="handleClick()" tabindex="0" class="btn-primary">
 Click Me
</button>

Inline Styles in JSX

When using inline styles in JSX, CSS properties must be written as JavaScript object properties using camelCase. Where you'd write background-color: #fff in CSS, in JSX it becomes backgroundColor: '#fff'. This applies to all CSS properties with hyphens, transforming font-size to fontSize, margin-top to marginTop, and text-align to textAlign. The style value itself must be a JavaScript object, typically written as an inline object literal.

// Inline styles in JSX
const styles = {
 backgroundColor: '#f5f5f5',
 fontSize: '16px',
 textAlign: 'center',
 marginTop: '20px'
};

<div style={styles}>Content</div>

// Or inline object
<div style={{ backgroundColor: '#f5f5f5', fontSize: '16px' }}>
 Content
</div>

Boolean Attributes

In HTML, boolean attributes like disabled, checked, and readonly can be written without values. In JSX, these attributes must receive a value. The convention is to use the attribute name directly as the value, which JavaScript evaluates to true. For example, <input disabled /> in HTML becomes <input disabled={true} /> or simply <input disabled /> in JSX. This ensures explicit control over attribute values and prevents unexpected behavior.

// Boolean attributes in JSX
<input type="text" disabled />
<input type="checkbox" checked={isChecked} />
<button disabled={isSubmitting}>Submit</button>

The Single Root Requirement

React components must return a single root element, which often surprises developers coming from traditional HTML backgrounds where multiple sibling elements at the top level of a document are perfectly valid. This requirement stems from how React's reconciliation algorithm works--it expects a single tree structure to compare and update. When you return multiple sibling elements from a component, React doesn't know how to reconcile them as a coherent unit, leading to compilation errors that prevent your application from running.

Using Fragments

React fragments provide an elegant solution to this problem. Fragments, written as <></> or <React.Fragment></React.Fragment>, allow you to group elements without adding extra nodes to the DOM. The short syntax <> is preferred for most cases since it's concise and accomplishes the same goal. When rendered, fragments simply disappear from the DOM tree, leaving their children as direct siblings. This behavior makes fragments ideal for returning multiple elements while maintaining clean DOM structure and avoiding conflicts with CSS layouts.

// Using a container div (adds extra DOM node)
function WithContainer() {
 return (
 <div>
 <h1>Title</h1>
 <p>Description</p>
 </div>
 );
}

// Using fragments (no extra DOM node)
function WithFragment() {
 return (
 <>
 <h1>Title</h1>
 <p>Description</p>
 </>
 );
}

// Using React.Fragment when you need a key
function List({ items }) {
 return items.map(item => (
 <React.Fragment key={item.id}>
 <dt>{item.term}</dt>
 <dd>{item.definition}</dd>
 </React.Fragment>
 ));
}

When to Use Fragments vs Container Elements

Choose fragments when you need to return multiple elements without affecting layout or styling. Fragments are ideal for components that serve as logical groupings, such as form fields, list items with multiple parts, or sections that semantically belong together but don't need a wrapper element. Use container elements like <div> when you actually need to apply styles, classes, or event handlers to a wrapper, or when you need the container for CSS layout purposes like flexbox or grid. The key consideration is whether an extra DOM node would cause issues with your styling or create unnecessary complexity in your component tree. For most UI components, fragments should be your default choice, with container elements used only when explicitly needed.

The performance difference between fragments and container elements is negligible in most cases--React's reconciliation is efficient regardless. However, in component trees with frequent updates or deeply nested structures, the reduced DOM depth from using fragments can contribute to slightly better performance and easier debugging. When building reusable component libraries, prefer fragments to give consumers maximum flexibility in how they arrange your components in their layouts.

Embedding JavaScript Expressions in JSX

The true power of JSX emerges when you combine markup with JavaScript expressions using curly braces. These curly braces create an escape hatch from JSX's markup syntax back into JavaScript, allowing you to embed dynamic values, perform calculations, and execute functions within your UI code. This integration is what makes React components so expressive--you can build complex, data-driven interfaces using familiar syntax patterns that feel natural to JavaScript developers.

Any valid JavaScript expression can appear inside curly braces in JSX. This includes simple variable references, function calls, arithmetic operations, ternary expressions, array methods like map() and filter(), and even other component function calls. The expression is evaluated, and its result is inserted into the JSX at that position. If the expression evaluates to a primitive value like a string or number, it renders as text. If it evaluates to a React element or component, that element is rendered in place.

When working with dynamic data, you'll often pass values through React props from parent components, then display those values using JSX expressions. This pattern of props-down-expressions-up forms the foundation of React's data flow architecture.

function UserProfile({ user, isAdmin }) {
 return (
 <div className="profile">
 <h1>{user.name}</h1>
 {/* Variable reference */}
 <p>Email: {user.email}</p>

 {/* Ternary for conditional rendering */}
 <p>Status: {isAdmin ? 'Administrator' : 'Regular User'}</p>

 {/* Logical AND for conditional elements */}
 {user.badge && <span className="badge">{user.badge}</span>}

 {/* Array mapping for lists */}
 <ul>
 {user.roles.map(role => (
 <li key={role}>{role}</li>
 ))}
 </ul>

 {/* Function calls */}
 <p>Joined: {formatDate(user.joinDate)}</p>

 {/* Inline calculations */}
 <p>Score: {user.correctAnswers * 10}</p>
 </div>
 );
}

Common Expression Patterns

Several expression patterns appear frequently in professional React codebases. For conditional rendering, the logical AND operator works when you want to show something or nothing, while ternary operators choose between two different elements. Early returns let you exit a component entirely when conditions aren't met. Array methods like map() transform data into JSX elements, filter() removes unwanted items before rendering, and reduce() aggregates data for summary displays. For complex conditional logic, consider extracting the logic to a helper function or custom React hook to keep your JSX clean and readable.

// Common expression patterns
function Dashboard({ user, notifications, items }) {
 // Guard clause with early return
 if (!user) return null;

 return (
 <div className="dashboard">
 {/* Filter and map combined */}
 <section>
 <h2>Active Items</h2>
 <ul>
 {items
 .filter(item => item.status === 'active')
 .map(item => (
 <li key={item.id}>{item.name}</li>
 ))}
 </ul>
 </section>

 {/* Conditional class composition */}
 <div className={`status ${user.online ? 'online' : 'offline'}`}>
 {user.online ? 'Online' : 'Offline'}
 </div>

 {/* Reduce for aggregations */}
 <p>Total: {items.reduce((sum, item) => sum + item.value, 0)}</p>

 {/* Optional chaining for safe access */}
 <p>Manager: {user.manager?.name || 'None'}</p>
 </div>
 );
}

Avoiding Expressions with Side Effects

While you can technically put any JavaScript expression inside curly braces, it's important to understand what belongs in JSX expressions and what doesn't. Expressions should be pure--they should compute and return a value without causing side effects. This constraint exists because React may evaluate expressions multiple times during different phases of the rendering process, and side effects in these evaluations can lead to unpredictable behavior, infinite loops, or performance problems.

Side effects like variable assignments, increment operations, or function calls that modify state should not appear directly in JSX expressions. Instead, handle these in event handlers, effects, or other appropriate lifecycle locations. The distinction isn't always obvious--for example, calling a method that only reads data is fine, but calling a method that modifies state is not. When in doubt, ask whether the expression could be safely called multiple times without changing anything other than its return value. If the answer is no, find a different place for that code.

// BAD: Side effect in expression (may be called multiple times)
function BadExample({ items }) {
 return (
 <ul>
 {items.forEach(item => console.log(item))} {/* Console log is a side effect! */}
 {items.map(item => <li key={item.id}>{item.name}</li>)}
 </ul>
 );
}

// BAD: Assignment in expression
function AlsoBad() {
 return <div>{result = calculateValue()}</div>; {/* Assignment is a side effect */}
}

// GOOD: Pure calculations in expressions
function GoodExample({ items, filter }) {
 const filteredItems = items.filter(item => item.category === filter);
 const itemCount = filteredItems.length;

 return (
 <div>
 <p>Showing {itemCount} items</p>
 <ul>
 {filteredItems.map(item => <li key={item.id}>{item.name}</li>)}
 </ul>
 </div>
 );
}

JSX and React Element Creation

Underneath the comfortable syntax of JSX lies a compilation process that transforms your markup into JavaScript function calls. Understanding this transformation helps you debug issues, optimize performance, and fully leverage JSX's capabilities. Every piece of JSX you write compiles to a call to React.createElement(), which returns a plain JavaScript object describing what should appear on screen. These objects are called React elements, and they form the basis of React's declarative approach to UI construction.

The React.createElement() function takes three parameters: the type of element to create, an object containing props (or null if there are none), and a variable number of children elements. When you write <div className="container"><p>Hello</p></div>, it compiles to React.createElement('div', { className: 'container' }, React.createElement('p', null, 'Hello')). The type can be a string for built-in elements like div, span, or button, or it can be a function or class reference for custom components.

This compilation happens during your build process, typically using Babel. The resulting JavaScript is what browsers actually execute, and it's why you need to include React in your bundle even when using JSX--React provides the createElement function that your JSX compiles to. Modern build tools and frameworks handle this automatically, but it's worth understanding that JSX is fundamentally a syntactic convenience that makes the underlying JavaScript more readable and maintainable.

// What you write (JSX)
function Welcome({ name }) {
 return <div className="welcome">Hello, {name}!</div>;
}

// What it compiles to (simplified)
function Welcome({ name }) {
 return React.createElement(
 'div',
 { className: 'welcome' },
 'Hello, ',
 name,
 '!'
 );
}

// The resulting React element object (conceptual)
{
 type: 'div',
 props: {
 className: 'welcome',
 children: ['Hello, ', name, '!']
 }
}

Implications for Component Design

Understanding how JSX compiles to React elements has practical implications for how you design and structure components. Because each JSX expression becomes a function call, deeply nested JSX creates nested function calls, which has performance implications at scale. Component composition--breaking large components into smaller, reusable pieces--isn't just an organizational strategy; it's a way to keep your JSX structure shallow and performant.

When debugging, understanding the compilation process helps you interpret error messages and component stacks. If you see an error in React.createElement, you can trace it back to your original JSX to identify the source. React DevTools shows the compiled structure, but understanding the mapping between JSX and the underlying calls makes debugging more intuitive. The element type in DevTools corresponds directly to what you wrote in your JSX, whether that's a built-in element like div or a custom component function name.

Performance optimization also benefits from this understanding. Flattened component structures with clear boundaries between parent and child responsibilities let React skip work more effectively. When React determines that a component hasn't changed, it doesn't need to examine its children in detail, which is why proper component boundaries matter for performance as well as code organization. Each level of nesting adds to the depth of the diffing algorithm, and changes near the bottom of the tree require traversing from the root to identify affected nodes. Keeping your JSX shallow through proper component composition directly improves reconciliation performance.

Component children also matter in ways that HTML doesn't prepare you for. In HTML, element content is just text. In React, children can be any JavaScript value, including other components, arrays of elements, or null/undefined. This flexibility enables powerful patterns like render props and component composition, but it also means you need to think about what your component accepts as children and how it renders them. The children prop isn't special in any compile-time sense--it's just another prop that happens to receive the content between your component's tags. This insight leads to more flexible component APIs that leverage composition over inheritance.

Best Practices for Writing Maintainable JSX

Writing good JSX is about more than correctness--it's about creating code that's readable, maintainable, and follows consistent patterns that your team can rely on. Adopting these practices from the start prevents technical debt and makes onboarding new developers easier. The goal is to make your JSX self-documenting, where the structure clearly communicates intent without requiring extensive comments or investigation.

Formatting and Structure

One of the most impactful practices is formatting multi-line JSX with consistent indentation and, when spanning multiple lines, wrapping the JSX in parentheses. This isn't just aesthetics--proper formatting makes it immediately clear which opening tag pairs with which closing tag, reducing cognitive load and preventing bugs. Most code formatters including Prettier handle this automatically, but understanding the principle helps you recognize poorly formatted code when you see it.

Consistent readability. Group related attribute ordering also improves attributes together and consider ordering them by importance or function. A common pattern places key first (for list items), followed by ref if used, then props, then event handlers and className/style. Within each group, attributes can be alphabetical or ordered by importance. The specific order matters less than having a consistent order that your team agrees on.

Breaking long JSX trees into smaller components serves both readability and performance. When a function or component exceeds a certain length--commonly suggested as 50-100 lines--it's often a signal that something should be extracted. Child components can have their own focused responsibilities, making the overall structure easier to understand and making it simpler to add features or fix bugs because each piece does one thing well.

// Well-formatted, readable JSX
function UserCard({ user, onEdit, onDelete }) {
 return (
 <article className="user-card">
 <header className="card-header">
 <img
 src={user.avatarUrl}
 alt={`${user.name}'s avatar`}
 className="avatar"
 />
 <div className="user-info">
 <h2 className="user-name">{user.name}</h2>
 <p className="user-role">{user.role}</p>
 </div>
 </header>

 <section className="card-body">
 <p className="user-bio">{user.bio}</p>
 <div className="user-stats">
 <span>Posts: {user.postCount}</span>
 <span>Followers: {user.followerCount}</span>
 </div>
 </section>

 <footer className="card-footer">
 <button onClick={() => onEdit(user.id)} className="btn-edit">
 Edit
 </button>
 <button onClick={() => onDelete(user.id)} className="btn-delete">
 Delete
 </button>
 </footer>
 </article>
 );
}

Additional Best Practices

Use TypeScript for prop types: TypeScript catches type errors at compile time and provides IDE support for auto-completion and documentation. Define interfaces for your component props and leverage TypeScript's JSX support for type checking.

Extract complex logic: If your JSX contains complex conditional logic or calculations, extract them to variables or helper functions before embedding them in JSX. This improves readability and makes the logic easier to test.

Use meaningful prop names: Choose prop names that clearly communicate purpose. Avoid generic names like data or items when more specific names like users or products would clarify the component's purpose.

Keep components focused: Each component should do one thing well. If a component is trying to handle too many responsibilities, break it into smaller, more focused components that compose together.

// PROPS: Use TypeScript for type safety
interface UserCardProps {
 user: User;
 onEdit: (id: string) => void;
 onDelete: (id: string) => void;
}

// LOGIC: Extract complex calculations
const userStatus = isOnline ? 'Online' : 'Offline';
const displayName = user.nickname || user.name;

// COMPOSITION: Break into focused components
function UserProfile({ user }) {
 return (
 <div>
 <UserAvatar user={user} />
 <UserInfo user={user} />
 <UserActions user={user} />
 </div>
 );
}

Performance Considerations for JSX

While JSX itself is highly optimized and the compilation process adds no runtime overhead, the structure and composition of your JSX affects how efficiently React can update the DOM. Understanding these performance implications helps you make informed decisions about component structure and avoid common performance pitfalls. In most cases, React's default behavior is fast enough, but in complex applications with deep component trees or frequent updates, these considerations become important.

Avoiding Unnecessary Re-renders

When a parent component re-renders, all of its children re-render by default, regardless of whether their props changed. This behavior ensures consistency but can cause performance problems when child components are expensive to render. React provides several tools to address this: React.memo() for function components, shouldComponentUpdate() for class components, and React hooks like useMemo() and useCallback() for memoizing expensive computations and stable function references.

The JSX structure you write directly affects these patterns. When passing objects or arrays as props, new references are created on each render, causing memoization to fail unless you properly memoize the creation. This is why spreading large objects as props (<Component {...largeProps} />) can be problematic--the entire object is treated as a new prop on each render. Instead, pass individual props for values that don't change, and memoize object creation at the parent level.

// PROBLEM: New object reference on each render
function Problematic({ items }) {
 // This object is recreated on every render!
 const config = { threshold: 0.5, maxItems: 10 };
 return <List items={items} config={config} />;
}

// BETTER: Memoize the object
import { useMemo } from 'react';

function Better({ items }) {
 const config = useMemo(() => ({ threshold: 0.5, maxItems: 10 }), []);
 return <List items={items} config={config} />;
}

// BEST: Pass individual props when possible
function Best({ items, threshold, maxItems }) {
 return <List items={items} threshold={threshold} maxItems={maxItems} />;
}

Virtualization for Long Lists

Virtualization addresses performance issues when rendering long lists by only rendering items currently visible in the viewport. Libraries like react-window and react-virtualized implement this pattern, creating a dramatically better experience for users scrolling through hundreds or thousands of items. Without virtualization, rendering thousands of DOM nodes--even if most are off-screen--causes significant memory pressure and slows down interaction.

Virtualization works by measuring the total list height and rendering only the items that would appear in the current scroll position. As users scroll, items are recycled and repositioned rather than created and destroyed. This technique reduces memory usage and improves scroll performance dramatically for large lists. For simple lists of 100 items or less, virtualization is usually unnecessary, but for feeds, tables, or catalogs with thousands of items, it's essential.

import { FixedSizeList as List } from 'react-window';

function VirtualizedList({ items }) {
 const Row = ({ index, style }) => (
 <div style={style} className="list-item">
 {items[index].name}
 </div>
 );

 return (
 <List
 height={600}
 itemCount={items.length}
 itemSize={50}
 width="100%"
 >
 {Row}
 </List>
 );
}

Production Builds

Development builds of React include extensive warnings designed to help you catch common mistakes and anti-patterns. While invaluable during development, these warnings add size and slow down your application. Always deploy production builds to your users, which strip out these warnings and minify your code for optimal performance. Create React App, Vite, Next.js, and other modern frameworks handle this automatically when building for production.

Code Splitting

Code splitting using React.lazy() and Suspense allows you to load components only when they're needed, reducing initial bundle size and improving page load times. This is particularly valuable for routes or features that aren't needed immediately, like modals, dashboards, or heavy interactive components. Combined with route-based splitting, you can significantly reduce the JavaScript that users need to download upfront.

import { Suspense, lazy } from 'react';

// Lazy load heavy components
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const Dashboard = lazy(() => import('./Dashboard'));

function App() {
 return (
 <Suspense fallback={<Loading />}>
 <HeavyComponent />
 <Dashboard />
 </Suspense>
 );
}

Common Mistakes and How to Avoid Them

Even experienced React developers occasionally make mistakes with JSX, and understanding common pitfalls helps you recognize and fix them quickly. Some mistakes cause obvious errors that prevent your code from running, while others introduce subtle bugs that only appear in specific circumstances. Learning to avoid these mistakes from the start saves time debugging and prevents bad habits from forming.

Most Common JSX Mistakes

// MISTAKE: Using HTML attribute names
// <div class="container" onclick={handleClick}></div>
<div className="container" onClick={handleClick}></div>

// MISTAKE: Forgetting to close tags
// <img src="logo.png" alt="Logo">
<img src="logo.png" alt="Logo" />

// MISTAKE: Incorrect self-closing syntax
// <br></br>
<br />

// MISTAKE: Missing keys in lists
// {items.map(item => <li>{item.name}</li>)}
{items.map(item => <li key={item.id}>{item.name}</li>)}

// MISTAKE: Confusing expressions and strings
// <img src={"./logo.png"}>
<img src="./logo.png" />
// <img src={logoUrl}> (where logoUrl is a variable)

// MISTAKE: Unintended falsy rendering
// {items.length && <span>{items.length} items</span>}
{items.length > 0 && <span>{items.length} items</span>}
// Or better: {items.length ? <span>...</span> : null}

// MISTAKE: Missing fragment wrapper
// return <li>First</li><li>Second</li> // Error!
return (
 <>
 <li>First</li>
 <li>Second</li>
 </>
);

Debugging JSX Errors

When JSX contains errors, React's error messages are generally helpful but can sometimes be cryptic, especially for newcomers. Understanding how to interpret these messages and common sources of errors helps you debug more efficiently. Most JSX errors fall into a few categories: syntax errors (missing closing tags, incorrect attribute names), type errors (passing wrong types to components), and runtime errors (code that runs but produces unexpected results).

Use TypeScript: TypeScript's JSX support includes type checking for props and children, catching many common mistakes at compile time. Define interfaces for your component props and let TypeScript validate what you're passing. This catches errors before they reach the browser and provides IDE support for finding and fixing issues.

Use ESLint: ESLint plugins like eslint-plugin-react add additional checks for common JSX mistakes, unused variables, and accessibility issues. Configuring your editor to run these tools on save catches errors immediately, often with helpful auto-fix capabilities. Essential rules include those that check for missing key props in lists, unused expressions, and potential accessibility problems.

Use React DevTools: React DevTools provides invaluable visibility into your component tree, showing exactly what JSX each component renders and what props it receives. When debugging rendering issues, checking whether a component receives the props you expect and renders the JSX you expect is often the fastest way to identify problems. DevTools also shows component updates, helping you understand why components re-render and identify unnecessary re-renders that might indicate performance problems.

Check console warnings: React provides helpful error messages in the browser console. Warnings about key props, missing dependencies in hooks, and deprecated APIs point you toward potential issues. Treat warnings as errors--fix them before they become bugs. The development build includes detailed warnings that help you catch problems early in development.

For deeper debugging, check the component stack trace in error messages. Each frame corresponds to a component in your tree, helping you trace the source of the error. When using custom hooks or HOCs, the component names can help you understand the call chain and identify where something went wrong.

Frequently Asked Questions About JSX

Ready to Build Better React Applications?

Our team of React experts can help you architect efficient component systems, optimize performance, and deliver exceptional user experiences.

Sources

  1. React.dev: Quick Start - Official React documentation covering JSX fundamentals, component creation, and markup syntax for user interfaces.

  2. freeCodeCamp: The React Handbook for Beginners - Comprehensive beginner guide covering JSX syntax, expressions, component patterns, and best practices.

  3. React.js: Optimizing Performance Documentation - Official React documentation on performance optimization, virtual DOM, and reconciliation.