React Fundamentals - JSX & Props

Learning Objectives
Students Will Be Able To: |
---|
Explain the Use Case of JSX |
Explain the Benefits that JSX Provides |
Use JSX to Define a Component's UI |
Render JS Expressions Into the DOM Using JSX |
Include Props in JSX |
Render an Array of Components |
Style Components Using the className & style Prop |
Road Map
- Setup
- JSX - What & Why?
- Review: JS Expressions
- Writing JS Expressions Into the DOM Using JSX
- JSX Itself is a JS Expression!
- What Are Props?
- Properly Rendering Arrays of Components
- Props for React Elements
- Intro to Styling React Elements
- Essential Questions
- Bonus Practice Exercise
Videos
1. Setup
This lesson builds upon the "React To-Do" sandbox we created in the previous lesson in codesandbox.io:

2. JSX - What & Why?
What?
-
JSX is an XML-like syntax extension to JavaScript. XML is short for extensible markup language and JSX is one of those extensions - just like HTML is.
-
Created by Facebook for use in React.
-
It provides a way to concisely define tree structures with attributes - perfect for defining a DOM tree!
-
It is transpiled into pure JavaScript.
❓ What is transpiling
Transpiling converts source code of one language into source code of another language. They are often referred to as source-to-source compilers. Compilers on the the other hand, convert source code into a form of executable code.
Why JSX?
-
It's simple and clear. Compared to pure JavaScript, JSX provides a more concise and better way to define a UI.
-
JSX resembles HTML, which allows us to more easily visualize the UI its JavaScript will create.
-
99.99% (a guess) of React apps are developed today using JSX to define the UI, not vanilla JS.
3. Review: JS Expressions
Before we learn how to render the result of a JS expression within JSX, let's review what JS expressions are...
JavaScript expressions evaluate to a single value/thing.
They can be used wherever a value is used, for example:
- Assigned to a variable
- Provided as an argument to a function call
- Returned from a function
Statements on the other hand, perform actions. A program's statements such as if
statements and for
/while
loops are not expressions.
4. Writing JS Expressions Into the DOM Using JSX
To write the result of a JS expression into the DOM within the JSX, we simply need to enclose the expression within curly braces.
Let's experiment by typing the the following within <ToDoList>
in our sandbox and observe the output:
function ToDoList() { const str = "SEI"; const score = 94; return ( <ul> <li>Number: {score}</li> <li>String: {str}</li> <li>Math.random(): {Math.random() * 100}</li> <li>Template Literal: {`${str} Rocks`}</li> <li>Ternary: {score > 90 ? "A" : "B or less"}</li> <li> Booleans, null & undefined: {true} {false} {null} {undefined} </li> <li>Logical &&: {score > 90 && <div>Got an 'A'!</div>}</li> </ul> ); }
The fact that React does not output the value of booleans, null
or undefined
can really come in handy, e.g., when using the logical &&
scenario for writing out an expression or not.
Objects and most of the built-in Objects (Date, Functions, RegExp, etc.) cannot be rendered as is - just their properties can be rendered. The practical exception are Arrays which we'll look at shortly.
5. JSX Itself is a JS Expression
Developing real-world React apps requires tooling to:
- Transpile the JSX into pure JS
- Import CSS
- Bundle the JS modules
The most popular transpiler for JSX is Babel. The following shows what a JSX expression transpiles into:

As you can see, JSX transpiles into a function call: React.createElement(...)
, which returns an object used by the React library.
Because JSX results in a function call that returns an object, JSX is a JavaScript expression! Thus, JSX can be assigned to variables, used in ternary expressions, etc.!
A Component Must Return a Single Root JSX Node
Because a function can only return a single expression, we must be sure to return a single root JSX node using the return
statement.
For example, the following will fail to compile:
function Whoops() { return ( <h1>Whoops</h1> <h2>No Dice!</h2> ); }
The function above is attempting to return two things, i.e., two objects which just isn't possible in JavaScript (or any other popular programming language).
The only solution used to be to wrap the sibling components with a single React Element such as a <div>
:
function GoodToGo() { return ( <div> <h1>Good To Go</h1> <h2>Dice Please!</h2> </div> ); }
The downside of the above approach is that this results in an extra, and perhaps unwanted <div>
rendered to the DOM which could impact layout/styling.
A better alternative if you don't want or need an extra wrapping React Element is React Fragments added in version 16.2 of React:
function GoodToGo() { return ( <> <h1>Good To Go</h1> <h2>Dice Please!</h2> </> ); }
👀 The
<> </>
syntax is shorthand for<React.Fragment> </React.Fragment>
👉 You Do - Render an Array (3 minutes)
- Define an array named
misc
before thereturn
statement that has the following elements:
- A string of your choosing
- A number of your choosing
- A boolean of
true
orfalse
- A React Element, e.g., a
<div>
with some content
- In ToDoList.jsx Add an
<li>
React Element and render the array as its content.
As you can see, React can render arrays. In fact, it's very common to render arrays of components, which we'll do in a bit.
6. What Are Props?
Very simply, props are used to pass information to components.
👀 "Information" can be any JS expression such as variables, functions, etc.
Basic Syntax
The syntax of passing props to a child component is much like defining attributes in an HTML element, for example, we can pass a simple string to a component like this:
<Person firstName="Fred" />
In the above example, the name of the prop is firstName
.
Because JSX is transpiled into pure JS, we use lowerCamelCasing to name props. This is contrary to the convention of kebob-casing used to name attributes in HTML.
Like HTML attributes, there should be no spaces before or after the =
sign.
There is no limit to the number of props that can be passed:
<Person
firstName="Fred"
age={21}
/>
Any JS expression can be passed, however, expressions other than simple strings (excludes template literals), are passed within curly braces. Thus, the age
prop will have the value set to the number 21
.
Each prop becomes a property on a "props" object that's passed to the child component.
The next example shows how you can pass an object literal and even a function:
function handleRaise(name, amount) {
// Give the person a raise!
alert(`${name.first} raised to ${amount}`);
}
<Person
name={{first: "Fred", last: "Arroyo"}}
age={21}
handleRaise={handleRaise}
/>
Don't let those double-curly braces ({{ ... }}
) confuse you. The outer curly braces simply say, "here comes a JS expression"; and the inner curly braces represent an object literal.
How the Child Components Access Props
A props object is passed to Function Components as an argument:
function Person(props) { return ( <div> <p>First: {props.name.first}</p> <p>Last: {props.name.last}</p> <p>Age: {props.age}</p> <button onClick={() => props.handleRaise(props.name, 9999)}> Give Raise! </button> </div> ); } // ignore the code below -> needed for live editor function handleRaise(name, amount) { // Give the person a raise! alert(`${name.first} raised to ${amount}`); } function View() { const name = { first: "Fred", last: "Arroyo" }; return <Person name={name} age={21} handleRaise={handleRaise} />; } render(<View />);
By convention, we name the parameter props
instead of tuna
, mamaMia
, etc.
As you can see, each passed prop becomes a property on the props
object that's passed to the Function Component as an argument.
If no props are passed to a component, props
will be an empty object.
👀 IMPORTANT: A prop's value should never be changed. Instead, a different value should be assigned to the prop at the source (the component that "owns" the info being passed).
Destructuring the props
Object
In modern JavaScript, it is common to create variables from properties on objects or elements in an array using Destructuring Assignment.
The syntax is similar to "unpacking" in Python.
Here's a simple example of using destructuring assignment to create variables for an object's properties:
function showCar() { const car = { make: "Tesla", model: "Model S", year: 2020, }; let { make, year } = car; return `${make} and ${year}`; //=> "Tesla" 2020 }
We can also use destructuring assignment to destructure parameters. Accordingly, it's common to destructure the props
object passed to a Function Component.
Using destructuring, the Person
component refactors to:
function Person({ name, age, handleRaise }) { return ( <div> <p>First: {name.first}</p> <p>Last: {name.last}</p> <p>Age: {age}</p> <button onClick={() => handleRaise(name, 9999)}>Give Raise!</button> </div> ); } // ignore the code below -> needed for live editor function handleRaise(name, amount) { // Give the person a raise! alert(`${name} raised to ${amount}`); } function View() { const name = { first: "Fred", last: "Arroyo" }; return <Person name={name} age={21} handleRaise={handleRaise} />; } render(<View />);
As you can see, the advantage is more concise code in the component's function.
Be sure to check the docs to learn more about destructuring objects and arrays!
Using Props in "React To-Do"
Currently in "React To-Do", the <ToDoList>
component is rendering two hard-coded <ToDoListItem>
components - this isn't very useful.
Instead, we typically would be passing actual data down via props...
Let's refactor "React To-Do" so that:
- App.js defines a
todos
array of strings representing the to-dos. - Pass the
todos
array to the<ToDoList>
component as a prop. - Refactor ToDoList.jsx to accept props.
- Use React Developer Tools to verify the prop in
<ToDoList>
. - Create and render a
<ToDoListItem>
component for each element (to-do) in thetodos
array. - Pass each "todo" string as a prop to the
<ToDoListItem>
. - Refactor the
<ToDoListItem>
component to destructure thetodo
prop and render it instead of the "To Do Item" placeholder text.
1. Define a todos
array in App.js
We can define the array outside of or within the function...
// App.js
import ToDoList from "./ToDoList";
// Add the todos array
const todos = [
'Have Fun',
'Learn React',
'Learn the MERN-Stack'
];
export default function App() {
👀 If we were to define the
todos
array within the Function Component, it would be "reset" (reassigned) every time the component rendered!
2. Pass the todos
array to the <ToDoList>
component as a prop
export default function App() {
return (
<div className="App">
<h1>React To-Do</h1>
{/* Pass todos as a prop */}
<ToDoList todos={todos} />
</div>
);
}
The name of the prop, todos
, can be anything you want (it does not have to match the value being assigned).
👀 Comments can be added within JSX by using the inline/multi-line syntax (
/* comment */
) wrapped with curly braces.
3. Refactor ToDoList.jsx to accept props
Now that <ToDoList>
is being passed a prop, it will need to be able to access it.
As previously discussed, Function Components need to define a parameter that by convention is named props
:
function ToDoList(props) { return ( <ul> <ToDoListItem /> <ToDoListItem /> </ul> ); } // ignore the code below -> needed for live editor function ToDoListItem() { return <li>ToDoListItem</li>; } function View() { return <ToDoList />; } render(<View />);
4. Use React Developer Tools to verify the prop in <ToDoList>
Open React Developer Tools and verify that the array has been passed!

👉 You Do - Destructuring (1 minute)
- Destructure the
props
object in the parameter list of ToDoList.jsx.
Hint: The name of the prop to destructure is
todos
.
5. Create and render a <ToDoListItem>
component for each element (the to-do string) in the todos
array
Our goal is to create and render a <ToDoListItem>
component for each string in the todos
array.
❓ What's the best array iterator method for transforming the elements of a source array into a new array?
Array.prototype.map
Here's one approach:
// remember to export default function ToDoList({ todos }) { // Create an array of <ToDoListItem> components const toDoListItems = todos.map((t) => <ToDoListItem />); return <ul>{toDoListItems}</ul>; } // ignore the code below -> needed for live editor const todos = ["Have Fun", "Learn React", "Learn the MERN-Stack"]; function ToDoListItem() { return <li>ToDoListItem</li>; } function View() { return <ToDoList todos={todos} />; } render(<View />);
The above approach is clean and it works. However, since calling the map()
method is a JS expression that results in an array, it's possible to perform the mapping within the JSX like this:
// remember the export default function ToDoList({ todos }) { return ( <ul> {todos.map((t) => ( <ToDoListItem /> ))} </ul> ); } // ignore the code below -> needed for live editor const todos = ["Have Fun", "Learn React", "Learn the MERN-Stack"]; function ToDoListItem() { return <li>ToDoListItem</li>; } function View() { return <ToDoList todos={todos} />; } render(<View />);
Both approaches are acceptable.
6. Pass each "todo" string as a prop to the <ToDoListItem>
👉 You Do - Pass a todo
Prop (1 minute)
- From
<ToDoList>
, pass each "todo" string as a prop namedtodo
to each<ToDoListItem>
.
Hint: In the mapping, the
t
parameter is the "todo" string
-
Use React Developer Tools to verify:
7. Refactor the <ToDoListItem>
component to destructure the todo
prop and render it instead of the "To Do Item" placeholder text
👉 You Do - More Prop Destructuring (1 minute)
- You got this!
Nice!

7. Properly Rendering Arrays of Components
Even though the array of <ToDoListItem>
components is rendering fine, the Console shows the following warning:

Whenever an array of components is rendered, React wants a special key
prop added to each component so that it can more efficiently track changes when re-rendering.
The value assigned to the key
prop must be unique among the array of components being rendered.
Since the user might enter the same To Do string, we can resort to using the index of the iteration:
export default function ToDoList({ todos }) {
return (
<ul>
{todos.map((t, idx) => (
<ToDoListItem todo={t} key={idx} />
))}
</ul>
);
}
In this case, we are using the index of iteration as the key
's value because we can't guarantee that the to-do strings would be unique. However, if the data, for example, had an id
, or another unique property, you should assign that value to the key
instead.
👀 The
key
prop is internal to React and cannot be accessed by the component it's being passed to.
8. Props for React Elements
❓ What are React Elements?
React Elements are React's built-in components that emit DOM elements into the page.
Many props provide the same purpose as their corresponding HTML attributes.
For example, if you wanted to assign an id
to a <div>
:
<div id="board">{/* contents of the board */}</div>
However, some props have differences as compared to their HTML equivalents.
For example, we can style React Elements using two props similar to their HTML counterparts:
className
: Works like the HTMLclass
attribute, simply named differently.style
: Performs styling using the HTMLstyle
attribute, but must be passed an object.
9. Intro to Styling React Elements
❓ Only React Elements can be styled, not user-defined components - why?
User-defined components do not actually find their way into the DOM, only React Elements do. For example, you would never see a <ToDoList>
tag in the DOM 🙂
Let's take a look at the basics of styling in React...
Including CSS Stylesheets in a React App
CSS stylesheets can be included in a React app by simply importing them as shown in App.js:
import "./styles.css";
This is only made possible by the tooling, in this case, Webpack, has been configured.
When imported as shown above, all defined CSS rules will be included "globally".
For example, let's create a ToDoListItem.css stylesheet in the "React To-Do" project:

Next, using the same syntax as used in App.js, let's import ToDoListItem.css in ToDoListItem.jsx:
// ToDoListItem.jsx
// Import the styles - making them available globally
import "./ToDoListItem.css";
Again, importing a stylesheet includes its styles globally - it does not matter which component module the stylesheet is imported in. Also, it does matter not how many times the same stylesheet is imported, its styles will only be bundled in the resulting global CSS once.
❓ Why bother creating stylesheets for components since we can just put all of the styles in a single stylesheet like styles.css?
It's a great way to organize CSS rules that apply only to a given component!
Whereas styles.css
is a great place for general, application-wide CSS.
Styling With the className
Prop
Note the outer <div>
in the <App>
component:
export default function App() {
return (
<div className="App">
<h1>React To-Do</h1>
<ToDoList todos={todos} />
</div>
);
}
The className
prop is used to assign a CSS class or classes to a React Element.
className
is used instead of since class
because it's a reserved word in the JS language. So React uses className
instead which just happens to be the same property name used on DOM elements.
If you accidentally use a prop of class
instead of className
, the component will still render as expected, however, a warning will appear in the Console.
Let's add some CSS rules within ToDoListItem.css:
.ToDoListItem {
margin: 4vmin;
padding: 2vmin;
border: 1vmin solid purple;
list-style: none;
font-size: 6vmin;
}
❓ Why are we defining a class named ToDoListItem
instead of using a simpler name such as list
?
To prevent name collisions between classes defined elsewhere.
Finally, let's add the ToDoListItem
CSS class to the <li>
React Element in ToDoListItem.jsx:
export default function ToDoListItem({ todo }) {
return (
<li className="ToDoListItem">{todo}</li>
That's better!

👀 Tip: We don't have to assign a simple string to
className
. We can compute and assign CSS class name(s) dynamically by using any JS expression within curly braces - ternary expressions, template literals, etc.!
👉 You Do - Use Another Stylesheet (5 minutes)
Although the list is looking better, notice that the it's slightly shifted to the right. This is because HTML <ul>
elements have some left padding by default.
-
Create a new stylesheet for the
<ToDoList>
component following the same conventions used above. -
Import the new stylesheet into ToDoList.jsx.
-
In the stylesheet, define a CSS class that sets
padding-left
to0
. -
Apply that class to the
<ul>
React Element.
Styling Using the style
Prop
The use of the className
prop is generally the go to for styling, however, in cases where individual CSS property values might change with every render, the style
prop provides maximum flexibility for highly dynamic styling!
The style
prop in React differs from its HTML counterpart in that it must be assigned a JS object instead of a string value.
To demo its use, let's say we want to alternate the background color of each To Do based on whether its index is odd or even.
So the next thing we need to ask ourselves is:
How will each <ToDoListItem>
component know if its odd or even?
Well, we're certainly going to have to pass an additional prop from its parent, <ToDoList>
.
Further, we have two options, we can pass the actual index of the iteration or pass a computed prop like isOdd
.
The first option, passing the index, provides a bit more flexibility because maybe we'll want to use it for other purposes, like displaying the number of the To Do.
👉 You Do - Pass the Index of the Iteration (2 minutes)
-
Pass the index of the map iteration (
idx
parameter) to each<ToDoListItem>
component using a prop namedindex
. -
In ToDoListItem.jsx, destructure the
index
prop being passed to it.
Now let's use the style
prop, assigning it an object literal to style the background color of the <ul>
:
function ToDoListItem({ todo, index }) { return ( <li className="ToDoListItem" style={{ backgroundColor: index % 2 ? "lavender" : "plum", }} > {todo} </li> ); } // ignore the code below -> needed for live editor function View() { return <ToDoListItem todo="testing" index={2} />; } render(<View />);
Of course, you can use any named color, hex code, or rgba()
value you wish - just be sure to quote it. Also, any numeric value assigned to a CSS property uses px
as its unit by default.

Using Chrome DevTools confirms that the style
prop results in a style
attribute being added to the DOM elements.
Styling Using CSS Modules
CSS Modules provide an alternative to importing stylesheets the way we have done thus far.
Classes defined in CSS Modules are dedicated to the component they are imported within, thus they have the advantage of avoiding name collisions.
However, they are not as flexible because they only work with class selectors.
Read this article to learn more.
Updated Fundamentals of React Chart
Before wrapping up with the Essential Questions, let's review the following updates to the Fundamentals of React Chart...
React Fundamental | Summary |
---|---|
... | ... |
JSX |
|
... | ... |
Props |
|
Styling |
|
10. ❓ Essential Questions (3 mins)
(1) True or False: JSX provides a clear, declarative approach to defining user interfaces.
True
(2) True or False: React Elements are built-in components that become actual HTML elements in the page's DOM.
True
(3) Information is passed down through the component hierarchy using _______.
Props
function ListItem({ item, index }) {
index = index + 1;
return (
<div>
{index}: {item}
</div>
);
}
(4) What is wrong with the above code?
Props such as index
are immutable - we don't update them.
const colors = ["red", "green", "blue"];
function ColorList() {
return colors.map((c) => <div>{c}</div>);
}
(5) The above <ColorList>
component will render as expected, however, a warning will appear in the Console - why?
<ColorList>
component will render as expected, however, a warning will appear in the Console - why?Components rendered as an array need a unique key
prop.
function BookItem({ book }) {
return (
<article class="BookItem">
<div>Title - {book.title}</div>
<div>Author - {book.author}</div>
</article>
);
}
(6) The above <BookItem>
component will render as expected, however, a warning will appear in the Console - why?
<BookItem>
component will render as expected, however, a warning will appear in the Console - why?The class
prop should be className