LearnContact
Lesson 1020 min read

React Elements

Learn what a React element really is under the hood, how it differs from a component, why elements are immutable, and how they get rendered to the DOM.

Introduction

You have written JSX and seen it compile down to React.createElement() calls. But what does React.createElement() actually return? Understanding the answer clears up a lot of confusion about how React works — and about the difference between an "element" and a "component," two words that sound similar but mean very different things.

This lesson looks at what a React element really is, how it differs from a component, why elements cannot be changed once created, and how React finally turns them into real, visible DOM nodes on the page.

What You Will Learn
  • What a React element actually is under the hood.
  • The distinction between an element and a component.
  • Why elements are immutable, and what that means in practice.
  • How createRoot().render() turns an element into real DOM nodes.

What Is a React Element?

A React element is not a real DOM node, and it is not anything drawn on screen by itself. It is a plain, lightweight JavaScript object that describes what should appear on screen — a tag name, its props, and its children, nothing more.

JSX You Write
const heading = <h1 className="title">Hello, React!</h1>;
The Element It Creates (Simplified)
const heading = {
  type: "h1",
  props: {
    className: "title",
    children: "Hello, React!"
  }
};
console.log(heading)
{ type: "h1", props: { className: "title", children: "Hello, React!" } }

That is genuinely all an element is — a description, like a blueprint or a photograph of what one piece of UI should look like at this moment. React reads these objects to figure out what the real DOM should contain; the objects themselves never touch the browser directly.

Elements vs Components

It is easy to use "element" and "component" interchangeably at first, but they are different layers. A component is a JavaScript function (or class) that you write; an element is the plain object that a component returns when it runs.

Component

A reusable function you define, like function Greeting() { ... }. It contains logic and returns a description of UI.

Element

The plain object a component returns — <h1>Hello!</h1> compiled down to { type: "h1", props: {...} }.

Component Called Many Times

The same Greeting component can run many times, producing a different element object on each render.

Element Tree

A rendered UI is really a tree of nested element objects, with components at the top deciding what each branch contains.

A Component Returning an Element
function Greeting() {
  // This function is the component.
  return <h1>Hello, React!</h1>; // This JSX becomes the element it returns.
}

In short: you write components, and components produce elements. Every time a component runs, it creates a brand-new element (or tree of elements) describing what should currently be on screen.

Elements Are Immutable

Once a React element has been created, you cannot change its props or children — it is immutable, just like a number or a string in JavaScript. There is no method to update an existing element in place; instead, React creates an entirely new element to represent any updated UI.

You Cannot Mutate an Element
const element = <h1>Count: 0</h1>;

// element.props.children = "Count: 1"; // ❌ Not how React works — this has no effect on the UI

// Instead, a component re-runs and creates a brand-new element:
function Counter({ count }) {
  return <h1>Count: {count}</h1>; // ✅ A new element is created every render
}

This is exactly what happens whenever state changes: the component function runs again and returns a new element describing the updated UI. React then compares this new element against the previous one (the diffing process from the Virtual DOM) and updates only what actually changed in the real DOM.

Why Immutability Matters

Because elements never change after creation, React can safely compare an old element to a new one to figure out exactly what is different, without worrying that either object was silently modified somewhere else in the app.

Rendering Elements to the DOM

On their own, elements are just JavaScript objects sitting in memory — they do nothing until React is told to render them. That is the job of createRoot().render(), which you saw earlier in main.jsx.

src/main.jsx
import { createRoot } from 'react-dom/client';

const element = <h1>Hello, React!</h1>;

createRoot(document.getElementById('root')).render(element);
Resulting Real DOM
<div id="root">
  <h1>Hello, React!</h1>
</div>

createRoot() connects React to a real DOM node (here, the element with id "root"), and .render() takes an element — or, in practice, an entire component like <App /> — and walks its description to create and insert the matching real DOM nodes. Every future update follows the same idea: a new element tree is created, and React updates the real DOM to match it.

Common Mistakes

Avoid These Mistakes
  • Trying to directly mutate an element's props after creating it, expecting the screen to update.
  • Confusing a component (the function you write) with an element (the object it returns).
  • Assuming an element is already a real DOM node — it is only a description until React renders it.
  • Believing you need to call render() manually for every update — React handles re-rendering when state or props change.

Best Practices

  • Think of elements as immutable snapshots — never try to modify one directly.
  • Keep the mental model "components produce elements, elements describe UI" clear as you write more code.
  • Let React manage re-rendering; avoid reaching for direct DOM APIs to update content a component controls.
  • Remember that logging an element with console.log shows a plain object, which can help demystify how JSX works.
  • Treat createRoot().render() as a one-time setup step, not something you call repeatedly for updates.

Frequently Asked Questions

Is a React element the same as a DOM element?

No. A React element is a plain JavaScript object describing what should be on screen. A DOM element (like an actual <h1> node in the browser) is created later, when React renders that description.

Can I inspect what an element looks like as an object?

Yes — console.log() any JSX expression and you will see a plain object with type, props, and other internal fields, confirming it is not a live DOM node.

Why can I not just mutate an element to update the UI?

Elements are immutable by design. Updates happen by creating an entirely new element (usually by re-running a component), which React then compares to the previous one to find the minimal DOM changes needed.

Do I ever call React.createElement() directly?

Rarely. JSX compiles to these calls automatically, so in day-to-day React development you write JSX and let the build tool generate the createElement() calls for you.

What does createRoot().render() actually do?

createRoot() attaches React to a real DOM node, and .render() takes an element (or component) and creates the matching real DOM nodes inside it, keeping them in sync on future updates.

Key Takeaways

  • A React element is a plain JavaScript object describing what should appear on screen, not a real DOM node.
  • A component is a function you write; an element is what that function returns when it runs.
  • Elements are immutable — once created, you cannot change their props or children.
  • Updating the UI means creating a new element (usually via a component re-running), not mutating an old one.
  • createRoot().render() is what actually turns an element into real, visible DOM nodes.

Summary

Underneath every piece of JSX you write is a simple, immutable JavaScript object — the element. Components are the functions that produce these objects, and React's job is to read them and keep the real DOM in sync. This distinction between components, elements, and the real DOM is one of the most important mental models in all of React.

In this lesson, you learned what a React element actually is, how it differs from a component, why elements are immutable, and how createRoot().render() turns an element into real DOM nodes. Next, you will start building components of your own in depth.

Lesson 10 Completed
  • You understand a React element as a plain JavaScript object.
  • You can distinguish a component from the elements it returns.
  • You understand why elements are immutable and what that means for updates.
  • You know how createRoot().render() turns elements into real DOM nodes.
Next Lesson →

Components