What Is React? Components, Elements, and Declarative UI

Understand what React is and why it exists, grasp the component model and the idea of declarative UI, and learn the precise distinction between a React element, a component, and a DOM node.

React is a JavaScript library for building user interfaces out of small, reusable pieces called components. Before you write a single line of React code, it pays to understand the mental model it is built on: instead of telling the browser step by step how to change the screen, you describe what the screen should look like for any given piece of data, and React figures out how to make that happen.

React as a UI library, not a framework

React describes itself as 'a library for web and native user interfaces.' That word choice is deliberate: React's job is narrow and specific — it renders a tree of components to a target (the browser DOM, a native mobile view, even a terminal) and keeps that rendering in sync with your data over time. It does not dictate how you fetch data, route between pages, or manage every kind of application state; those concerns are handled by separate libraries (React Router, TanStack Query, Redux, Zustand, and so on) that you choose and add as needed.

This is different from an all-in-one framework that makes those decisions for you out of the box. React's minimalism is why it has such a large ecosystem: because the core library only solves 'turn data into UI and keep it updated,' the community has built countless tools around it for every other concern. When people say 'I'm building a React app,' they usually mean React plus a small stack of chosen companions — a bundler like Vite, a router, and perhaps a data-fetching library.

React was created at Facebook (now Meta) and open-sourced in 2013 specifically to solve the problem of keeping complex, frequently-changing UIs (like a live news feed) consistent with underlying data without hand-written DOM manipulation code turning into an unmaintainable mess.

Declarative UI vs. imperative UI

In traditional, imperative DOM programming, you write step-by-step instructions for exactly how to mutate the page: 'find this element, create a new <li>, set its text, append it to that <ul>, then remove the old error message if it exists.' As an application grows, the number of possible states and the transitions between them multiplies, and imperative code has to account for every single transition by hand. This is a common source of UI bugs — an element that should have been removed but wasn't, a class that never got toggled off.

React flips this around with a declarative model: you describe what the UI should look like for a given state, as a plain description (JSX, which you'll meet shortly), and React handles the imperative work of computing the minimal set of real DOM changes needed to get there. You write 'when isLoggedIn is true, render this welcome banner' rather than 'when the user logs in, create a banner element and insert it, and remember to remove it on logout.'

Concretely, this means your component's job is to be a pure function of its inputs: given the current data (props and state), return a description of the UI. You never write document.createElement or element.appendChild yourself in ordinary React code — you return JSX, and React translates that description into real DOM operations behind the scenes, only touching what actually changed.

The component model

A component is a self-contained, reusable building block of UI — most commonly written today as a plain JavaScript/TypeScript function that returns a description of what should appear on screen. A component can be as small as a single button or as large as an entire page; real applications are trees of components nested inside one another, from a top-level App component down to small leaf components like Avatar or Badge.

Components communicate with each other in two directions. Data flows down from parent to child through props (short for 'properties') — a read-only set of inputs a parent passes to configure a child, similar to arguments passed to a function. Components also manage their own internal, changing data through state, which a component owns privately and can update over time (for example, whether a dropdown is currently open). When state changes, React re-renders that component (and its children) to reflect the new data.

Components respond to user interaction through events — handlers you attach to elements (like onClick or onChange) that run your code when the user does something, typically to update state, which in turn triggers a re-render with the new UI description. This loop — data in via props/state, description out via JSX, events back in to update state — is the entire mental model of a React application, repeated at every level of the component tree.

Elements, components, and DOM nodes: three different things

These three terms are frequently confused by beginners, so it is worth being precise. A component is the reusable definition — a function (or, in legacy code, a class) that knows how to produce UI for given props and state. function Welcome() { ... } is a component; it is a piece of code, not yet any particular piece of UI on screen.

A React element is a plain, lightweight JavaScript object describing a piece of UI at a single point in time — the result of calling a component, or of writing JSX like <Welcome name="Ana" />, which compiles to React.createElement(Welcome, { name: "Ana" }). An element is immutable, cheap to create, and contains no methods or real browser behavior — it is just a description, like a blueprint, that says 'render a Welcome component with this prop.' Elements are recreated constantly (every render produces a fresh tree of them), which is fine because they are so lightweight.

A DOM node is the actual browser object that exists in the live page — the thing you'd see if you opened browser DevTools and inspected the Elements panel, with real properties like offsetHeight and real methods like addEventListener. React takes the tree of elements your components describe and, only where necessary, creates, updates, or removes real DOM nodes to match. You (almost) never touch DOM nodes directly in React code; React's rendering engine (ReactDOM, for web) manages that translation for you.

So the flow is: a component (code/definition) is invoked with some props and state, which produces React elements (a lightweight description), which React then reconciles against the existing DOM nodes (the real, on-screen browser objects), updating only what changed.

JSX compiles to element-creation calls

JSX is syntactic sugar — it always compiles down to function calls that produce plain objects (elements), never directly to DOM operations. Because an element is just data, React can compare an old element tree to a new one (a process called reconciliation) and compute the minimal real DOM changes needed, instead of rebuilding the page from scratch on every update.

// What you write (JSX):
const element = <h1 className="title">Hello, world</h1>;

// What it compiles to (roughly):
const element = React.createElement(
  "h1",
  { className: "title" },
  "Hello, world"
);

// The resulting 'element' is just a plain object, similar to:
// { type: "h1", props: { className: "title", children: "Hello, world" } }

Code Examples

Greeting is the component (reusable definition). <Greeting name="Ana" /> creates a React element (a lightweight description referencing that component and its props). Nothing touches the real page until React's rendering step turns that description into an actual <h1> DOM node. Expected result: Once rendered to the page, the browser shows: Hello, Ana!

// A component: a function that returns a description of UI
function Greeting({ name }: { name: string }) {
  return <h1>Hello, {name}!</h1>;
}

// Using the component produces a React element (a description),
// not yet any real DOM node:
const descriptionOnly = <Greeting name="Ana" />;

// Only when React actually renders this element into a page
// does a real <h1> DOM node get created in the browser:
// ReactDOM.createRoot(document.getElementById("root")!).render(descriptionOnly);

From data to pixels

Data flows into a component, which returns React elements (descriptions); React turns those descriptions into real DOM nodes, which the browser paints as the user interface.

Data            Component           React Elements        DOM              User Interface
[ props/state ] -> [ Greeting() ] -> [ {type:'h1', ... } ] -> [ <h1> node ] -> [ visible page ]
       |                  |                     |                    |                  |
   raw values      function that runs     lightweight, plain    real browser        what the
   your app owns    and returns JSX       description objects    object in memory    user sees

Important Rules

React describes UI declaratively: you say what the UI should look like for the current data, not the step-by-step operations to mutate it.

A component is code (a function); a React element is a lightweight description object produced by calling/using that component; a DOM node is the real, on-screen browser object React creates to match the element description.

Data (props) flows one direction: down from parent components to child components. Children talk back to parents through events and callback props, never by directly editing a parent's data.

Elements are cheap and recreated on every render — this is expected and by design, not a performance concern in itself.

Where this shows up

Understanding the element/component/DOM-node distinction is what makes React's behavior predictable instead of mysterious. It explains why re-rendering a component is cheap (you're just recreating lightweight description objects), why React can batch and optimize real DOM updates behind the scenes, and why tools like React DevTools show you a 'component tree' that is a step removed from the browser's own DOM inspector — they're genuinely different layers.

// Thinking JSX IS the DOM node const el = <h1>Hi</h1>; el.style.color = "red"; // Error: 'el' has no 'style' — it's a plain description object, not a live DOM node

// Style is described declaratively, as part of the element itself const el = <h1 style={{ color: "red" }}>Hi</h1>;

A React element is a plain JavaScript object with no browser behavior — it is not the live DOM node and has no DOM methods or properties. Any styling or attributes must be described declaratively as props on the element, not imperatively set afterward.

[multiple-choice] What best describes React's core job? A. It replaces JavaScript entirely with a new templating language B. It renders a tree of components and keeps that rendering in sync with data over time C. It is a full framework that also handles routing and data fetching by default D. It compiles TypeScript into JavaScript

B. It renders a tree of components and keeps that rendering in sync with data over time — React's core, narrow responsibility is turning component/data descriptions into a real UI and keeping it updated as data changes — routing, data fetching, and other concerns are handled by separate libraries you add on top.

[multiple-choice] Which statement correctly distinguishes a React element from a DOM node? A. They are the same thing, just different names B. A React element is a real browser object; a DOM node is a plain description C. A React element is a lightweight, immutable description object; a DOM node is the real, on-screen browser object React creates to match it D. A DOM node is created first, and React elements are generated from it

C. A React element is a lightweight, immutable description object; a DOM node is the real, on-screen browser object React creates to match it — An element is a plain description object with no browser behavior. React uses that description to create or update real DOM nodes, which are the actual objects the browser renders and that live in the page.

[predict-output] Given function Box() { return <div>Hi</div>; }, what does calling <Box /> inside JSX actually produce at that point (before any rendering to the page happens)? A. A real <div> DOM node inserted into the page immediately B. A React element — a lightweight description referencing the Box component C. Nothing — it throws an error until ReactDOM.render is called D. An HTML string

B. A React element — a lightweight description referencing the Box component — Writing <Box /> compiles to a React.createElement call, producing a plain description object (a React element). No real DOM node exists until React's rendering step processes that description.

In your own words (one or two sentences each), explain the difference between: (1) a component, (2) a React element, and (3) a DOM node. Then write a one-line component called Label that takes a text: string prop and returns a <span> containing that text.

function Label({ text }: { text: string }) { return <span>{text}</span>; }

A component is a definition/function; an element is a description produced by using that component; a DOM node is the real thing the browser eventually shows.