Skip to solution
easyPhone Screen

What is the difference between element and component in React?

656 views
01

Understand 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.

conceptsarchitecture
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for React interviews — assumes basic JSX familiarity. Difficulty: Easy to Medium

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Every object-shape claim below was produced by inspecting real valu

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

Inspecting an element, and what breaks when you call a component directly
Run Playground
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>
  );
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 14 of 119 decoded in the React.js track. One more won't hurt.

Back to track