Props
By now, one part of the shape is already visible:
- JSX attributes become entries in
props - nested JSX becomes
props.children
But that is still only the description side.
When the element's type is a component, those values still have to move from the element object into the component itself. That is the missing piece we will fill here.
Not positional arguments #
A natural first guess is that JSX attributes become ordinary function arguments.
So if we write:
<Greeting name="Ada" />
maybe the component receives the string 'Ada' directly.
That guess leads to this attempt:
function Greeting(name) { return <div>Hello {name}</div>; }
root.render(<Greeting name="Ada" />);
Waiting to run
Not run yet.
React is telling us that name is not the string child we expected. It is an object, and that object is not directly renderable as text.
So the first correction is:
a component does not receive each JSX attribute as a separate positional argument
There must be one more layer between JSX attributes and the component parameter.
The one object #
The smallest next step is to inspect the parameter directly:
function Greeting(value) { console.log(value); return <div>Hello</div>; }
root.render(<Greeting name="Ada" />);
Waiting to run
Not run yet.
Now the shape is visible.
The component receives one props object instead of one argument per JSX attribute.
So the correct mental model is:
- JSX attributes are collected into one object
- React passes that one object to the component
That object is what React calls props[1].
Attributes become fields #
If the component receives one object, the next question is simple:
where do multiple JSX attributes go?
function Greeting(props) { console.log(props); return ( <div> Hello {props.name} from {props.city} </div> ); }
root.render(<Greeting name="Ada" city="London" />);
Waiting to run
Not run yet.
They become fields on that same object. That gives us the basic rule:
component props are fields on one object passed into the component
So the parameter name props is just a conventional name for the object React passes in.
Same props as the element object #
We can now connect this back to our existing element model.
If JSX creates an element object, and its attributes become element.props, then the component should receive that same props object when React uses the component type.
We can inspect both sides:
function Greeting(props) { console.log('component received:', props); return <div>Hello {props.name}</div>; } const element = <Greeting name="Ada" />;
console.log('element props:', element.props); root.render(element);
Waiting to run
Not run yet.
This is the missing bridge.
On the description side, the element object contains:
{
type: Greeting,
props: {
name: 'Ada'
}
}
On the component side, React uses that props object as the component input.
That means the component is not receiving data from nowhere. It is receiving the props already stored on the React element object[2].
Destructuring #
Once we know the parameter is one object, there are two ordinary JavaScript ways to read it.
The first is field access:
function Greeting(props) {
return <div>Hello {props.name}</div>;
}
The second is destructuring:
function Greeting({ name, city }) { return ( <div> Hello {name} from {city} </div> ); }
root.render(<Greeting name="Ada" city="London" />);
Waiting to run
Not run yet.
This does not change React's behavior. It is just ordinary JavaScript unpacking the same props object.
So these two forms mean the same thing at the React level:
function Greeting(props) {
return <div>Hello {props.name}</div>;
}
function Greeting({ name }) {
return <div>Hello {name}</div>;
}
The difference is only how we read the object inside the component body.
Children #
There is still one more useful hole to fill.
We saw that nested JSX becomes props.children on the element object. Does a component receive children through some separate mechanism?
function Card(props) { console.log(props); return ( <section style={{ border: '1px solid currentColor', borderRadius: '0.6rem', padding: '0.65rem 0.8rem' }} > {props.children} </section> ); }
root.render( <Card> <strong>Hello</strong> from inside the card </Card> );
Waiting to run
Not run yet.
No. children is just another field on the same props object. That gives us a more complete picture:
- ordinary JSX attributes become fields such as
name,city, ortitle - nested JSX becomes the
childrenfield - all of them arrive through the same props object
So children is part of props.
Filling the hole #
At this point, we can describe the whole path precisely.
When we write:
<Greeting name="Ada" />
JSX produces a React element description whose type is Greeting and whose props include { name: 'Ada' }.
Then React uses that description and gives the component its input through that one props object.
So the right mental model is:
JSX attributes turn into the element's
props, and the component receives that props object as its input
And this is how props fit into the model we already built:
- elements are descriptions
- components are element types
- props are the input object carried by the element description into the component
Final definition #
Props are the object of input values React passes to a component. JSX attributes become fields on that object, and nested JSX becomes props.children.
So if we ask, "how does data get into a component?", the answer is:
data gets into a component through the props object
And if we ask, "where does that object come from?", the answer is:
it comes from the element description React created from JSX or
React.createElement(...)
Summary #
We started with the wrong guess that JSX attributes become positional function arguments. The failure showed that the component was receiving an object instead. Then we inspected that object and connected it back to the React element model.
That process gives us the answer:
- a component receives one props object, not one function argument per JSX attribute
- JSX attributes become fields on that props object
- the element object's
propsand the component's props are the same data at different points in the process - destructuring is just a JavaScript way to read props more directly
- nested JSX becomes
props.children
props are the input object that carries data from the element description into the component.
Notes
- The live demos in this article use the React 19.2.5 and react-dom 19.2.5 development bundles. Exact error messages and some runtime behavior may change in future React releases.