facebook/reactMITd083ec1Report / request removal

Element Types & Components

JSX is lowered into calls that package a type, props, children, and key into a React element. The element is a description whose type and props are carried forward.

JSX, createElement, and cloning converge on the same recognizable element construction path, while key, __self, and __source are handled separately from ordinary props.

Sources: packages/react/src/jsx/ReactJSXElement.js:170-283, packages/react/src/jsx/ReactJSXElement.js:610-746, packages/react/src/jsx/ReactJSXElement.js:748-764

Core concepts

React element

A React element is an object tagged by $$typeof with type, key, and props, plus development-only owner and debugging data.

Sources: packages/react/src/jsx/ReactJSXElement.js:170-283

Element type

The element type is the value passed as type; element creation preserves it and does not classify it as a class, function, or host component.

Sources: packages/react/src/jsx/ReactJSXElement.js:170-283, packages/react/src/jsx/ReactJSXElement.js:610-746

Reserved key

A key is normalized and stored on the element separately from ordinary props.

Sources: packages/react/src/jsx/ReactJSXElement.js:610-746, packages/react/src/jsx/ReactJSXElement.js:109-119

Children payload

Children are stored in props.children as one value for one child or an array when multiple child arguments are supplied.

Sources: packages/react/src/jsx/ReactJSXElement.js:610-746

Class component base

A class component instance receives props, context, refs, and an updater; the renderer later supplies the real updater.

Sources: packages/react/src/ReactBaseClasses.js:19-27

How JSX becomes an element

The JSX runtime has a development path that records owner/debug information and delegates to jsxDEVImpl. The implementation validates children, derives a key from the explicit argument or configuration, and then constructs the element through ReactElement.

return jsxDEVImpl(
  type,
  config,
  maybeKey,
  isStaticChildren,
  debugStackDEV,
  __DEV__ &&
    (trackActualOwner
      ? createTask(getTaskName(type))
      : unknownOwnerDebugTask),
);

This call passes the JSX type, configuration, key, static-children mode, and development diagnostics into the implementation.

The production JSX path reuses the incoming configuration when no key was spread, otherwise copies properties while removing key, then calls ReactElement(type, key, props, getOwner(), undefined, undefined). In development, jsxDEVImpl checks whether static children are an array, validates each child, and freezes that array when possible.

createElement follows a similar shape but accepts children as positional arguments. It extracts key, copies non-reserved configuration properties into a new props object, assigns one child directly, or creates and freezes an array for multiple children.

const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
  props.children = children;
} else if (childrenLength > 1) {
  const childArray = Array(childrenLength);
  for (let i = 0; i < childrenLength; i++) {
    childArray[i] = arguments[i + 2];
  }
  if (__DEV__) {
    if (Object.freeze) {
      Object.freeze(childArray);
    }
  }
  props.children = childArray;
}

The important distinction is that multiple positional children become one array-valued props.children; a single child remains the original value.

This diagram shows the data movement from JSX entry points into the element object.

JSX to React element — How do JSX inputs become an element object?

Evidence

Sources: packages/react/src/jsx/ReactJSXElement.js:441-467, packages/react/src/jsx/ReactJSXElement.js:469-604, packages/react/src/jsx/ReactJSXElement.js:291-348, packages/react/src/jsx/ReactJSXElement.js:489-509, packages/react/src/jsx/ReactJSXElement.js:685-701, packages/react/src/jsx/ReactJSXElement.js:170-283

What the element object contains

ReactElement treats props.ref as the source of truth for ref handling. In development, the object includes $$typeof, type, key, props, and _owner; in production, it includes $$typeof, type, key, ref, and props.

FieldMeaningDevelopment detail
$$typeofIdentifies the object as a React element.Uses REACT_ELEMENT_TYPE.
typeCarries the element type unchanged.It is also passed to getTaskName when development debug tasks are created.
keyCarries the normalized identity value.Stored separately from props.
propsHolds ordinary properties and children.Frozen with the element when possible.
_ownerRecords the component responsible for creation.Present in development only.

These fields are established by ReactElement; development also adds _store, _debugInfo, _debugStack, and _debugTask, then freezes the props and element objects when supported. The debug task path obtains a name from type through getTaskName.

isValidElement recognizes an element by checking that the value is a non-null object whose $$typeof equals REACT_ELEMENT_TYPE. This is the creation-time validity check for the element marker, not a class/function/host classification.

Sources: packages/react/src/jsx/ReactJSXElement.js:170-237, packages/react/src/jsx/ReactJSXElement.js:188-200, packages/react/src/jsx/ReactJSXElement.js:240-279, packages/react/src/jsx/ReactJSXElement.js:441-467, packages/react/src/jsx/ReactJSXElement.js:29-48, packages/react/src/jsx/ReactJSXElement.js:891-897

How keys and child arrays are preserved

createElement validates each positional child in development before it assembles the props object. The JSX development runtime validates a static child array item by item and freezes it, while dynamic children are validated as one child value.

The creation path calls hasValidKey before extracting and stringifying a configuration key. Its definition treats a key as valid when config.key is not undefined, while ignoring its own development warning getter. createElement excludes key, __self, and __source from copied props. In development, defineKeyPropWarningGetter warns that key is not a prop.

Child traversal derives explicit keys from element.key; when no explicit key exists, it derives an implicit key from the child index. Explicit keys are escaped, while implicit keys use the index in base 36. The traversal machinery uses SEPARATOR and SUBSEPARATOR as path delimiters, and escapeUserProvidedKey protects user-provided key segments.

When mapping produces a new element, mapIntoArray calls cloneAndReplaceKey so the mapped child receives the relevant key path. cloneAndReplaceKey reconstructs the element with the same type and props but a replacement key.

This sequence shows the key-validation call order in createElement.

createElement call order — In what order are children, keys, and the element object handled?

Evidence

Sources: packages/react/src/jsx/ReactJSXElement.js:610-631, packages/react/src/jsx/ReactJSXElement.js:489-509, packages/react/src/jsx/ReactJSXElement.js:656-665, packages/react/src/jsx/ReactJSXElement.js:109-119, packages/react/src/jsx/ReactJSXElement.js:667-681, packages/react/src/jsx/ReactJSXElement.js:121-141, packages/react/src/ReactChildren.js:74-93, packages/react/src/ReactChildren.js:32, packages/react/src/ReactChildren.js:33, packages/react/src/ReactChildren.js:63-65, packages/react/src/jsx/ReactJSXElement.js:748-764, packages/react/src/jsx/ReactJSXElement.js:610-746, packages/react/src/jsx/ReactJSXElement.js:864-882

Class, function, and host component boundaries

Element creation itself does not decide whether type represents a class component, function component, or host component. The constructor stores the supplied type on the element, while the creation path defers invalid-type handling because the renderer knows which types are valid for its environment.

The class contract visible here is the base Component initializer: it stores props and context, initializes refs, and installs either the supplied updater or ReactNoopUpdateQueue. PureComponent follows the same instance fields and updater setup, while its prototype is based on ComponentDummy. The supplied excerpts do not show the reconciler’s exact class-versus-function-versus-host classification branch.

Sources: packages/react/src/jsx/ReactJSXElement.js:170-193, packages/react/src/jsx/ReactJSXElement.js:610-625, packages/react/src/ReactBaseClasses.js:19-27, packages/react/src/ReactBaseClasses.js:132-138, packages/react/src/ReactBaseClasses.js:140

How it connects

The public react package exposes the element creation surface documented in Public API Reference. Element shape and $$typeof classification are detailed in react-is & Element Symbols.

The reconciler consumes the element description while building fibers, which is the boundary covered by Fiber Architecture and Render Phase. Its child-key behavior continues into Reconciliation Algorithm, where keys determine how child positions are compared.

Host-specific interpretation is renderer work: DOM element types connect to ReactDOM Host Config, while native element types connect to React Native Renderer (Fabric). Class lifecycle behavior is covered by Effects & Lifecycle.

Sources: packages/react/src/jsx/ReactJSXElement.js:170-283, packages/react/src/jsx/ReactJSXElement.js:610-746

Key takeaways

  • React elements carry $$typeof, type, key, and props; development adds owner and debugging metadata.
  • createElement stores one child directly and multiple children in a newly allocated array.
  • key is extracted from configuration and is not an ordinary prop.
  • Child traversal uses explicit keys or index-derived implicit keys, with escaping for path segments.
  • The shown element-creation code preserves type; it does not show the reconciler’s class, function, or host classification branch.

Want this for your repos?

Try Angada AI Wiki