Skip to the solution
EasyPhone Screen6 min read

What is the difference between element and component in React?

656 views

The problem

Question presented to candidate: "You keep hearing both words. What is the actual difference between a React element and a React component?"

What a strong answer should cover:

  • A component is a function (or class) that accepts props and returns a description of UI. It is a blueprint.
  • An element is the plain object that description actually is — a single instruction, produced by calling the component in JSX.
  • An element is not a DOM node and not a component instance; it is data.
  • The object shape: $$typeof, type, key, props. type is the function itself for a custom component, or a string like "h1" for a host element.
  • Elements are frozen and created fresh on every render — which is precisely why they are cheap and why diffing is just object comparison.
  • <Greeting /> is sugar for createElement(Greeting, ...); JSX produces elements, it does not call the component.
  • Signal of depth: React calls the component; you never do. That is why calling Greeting() directly breaks Hooks.

Clarifying questions expected:

  • "Do you want me to include what $$typeof is for?" (XSS protection for JSON-injected elements.)

Code / implementation expected: Optional, but showing createElement output next to JSX makes the point instantly.

  • concepts
  • architecture

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read · 8 sections

Try it in the playground

Open any example in the playground to run and change it.

ReactInspecting an element, and what breaks when you call a component directly
import { useState, createElement, isValidElement, cloneElement } from "react";

function Greeting({ name, children }) {
  return <p>Hello {name}! {children}</p>;
}

// A component with state — used below to show why you must NOT call it directly.
function Counter({ label }) {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>{label}: {n}</button>;
}

export default function App() {
  const element = <Greeting name="Ada" />;
  const viaFactory = createElement(Greeting, { name: "Ada" });
  const host = <h1>a host element</h1>;

  const facts = [
    ["typeof Greeting (component)", typeof Greeting],
    ["typeof element", typeof element],
    ["isValidElement(element)", String(isValidElement(element))],
    ["isValidElement(Greeting)", String(isValidElement(Greeting))],
    ["Object.keys(element)", Object.keys(element).join(", ")],
    ["element.type === Greeting", String(element.type === Greeting)],
    ["JSON.stringify(element.props)", JSON.stringify(element.props)],
    ["Object.isFrozen(element)", String(Object.isFrozen(element))],
    ["JSX and createElement match", String(element.type === viaFactory.type)],
    ["host.type (a string, not a fn)", JSON.stringify(host.type)],
    ["two identical elements are ===", String((<Greeting name="Ada" />) === (<Greeting name="Ada" />))],
  ];

  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6 }}>
      <h3>The element is just an object</h3>
      <table style={{ borderCollapse: "collapse", fontSize: 13 }}>
        <tbody>
          {facts.map(([k, v]) => (
            <tr key={k}>
              <td style={{ padding: "3px 12px 3px 0", color: "#555" }}>{k}</td>
              <td style={{ padding: "3px 0", fontFamily: "ui-monospace, monospace" }}>{v}</td>
            </tr>
          ))}
        </tbody>
      </table>

      <h3>cloneElement, because elements are frozen</h3>
      {cloneElement(element, { name: "Grace" }, <em>(props merged into a copy)</em>)}

      <h3>Let React call the component</h3>
      <Counter label="Correct — has its own state" />

      <p style={{ color: "#666", fontSize: 13, marginTop: 16 }}>
        Calling <code>Counter(&#123;label:"x"&#125;)</code> directly would inline its body into
        App, so its Hook would be attributed to App and it would not appear as
        its own component in DevTools. Always write &lt;Counter /&gt;.
      </p>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 14 of 119 in React.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All React.js questions
Up nextEasy

forwardRef removal — how do refs work as props in React 19?

Continue