- Lab
- Core Tech

Guided: React Foundations - JSX and Components
In this React Fundamentals: JSX and Components guided lab, you will learn the anatomy of a React application, how to read and write JSX, create components, reuse presentational structure, perform dynamic rendering, and create a minimal React helpdesk application.

Path Info
Table of Contents
-
Challenge
Overview
Welcome!
In this guided lab, you will migrate a minimal helpdesk application from HTML to React. As you perform migration tasks, you'll learn how JSX differs from HTML, and how React uses JSX to render components.
What to Expect
You do not need to know React before starting this lab, but you should be familiar with the fundamentals of web development with HTML, CSS, and JavaScript.
The JavaScript code in the lab is written in idiomatic React, which is typically ES2015+ syntax. You should be able to work with arrow functions, ES modules, and
const
.info> Stuck on a task? Check out the
solution/
folder in the project directory for full solution files and reference code for each step. Files with numbers (likeindex.2.jsx
) correspond to the task order in the step.Getting Started
To make sure the lab environment is set up and working, run the Globomantics Helpdesk demo application. Once set up, you can visit {{localhost:5173}} to view the app in your browser, or in the Web Browser tab in the editor to the right.
What you will see is a plain HTML and CSS webpage from the index.html file.
info> Web browser not working? Sometimes while reading through the lab, the dev server will shut down and you'll have to reconnect to the Terminal. Just run
npm run dev
again to start the server back up. Other times, the web browser may not always reflect the latest code due to the auto-save feature of the lab. Just click the refresh button next to the address bar in the tab to force-refresh the page.How is the app hosted?
You may wonder what "VITE" means and how the app is being hosted on the above URL. This comes from the JavaScript development tool Vite.js.
Vite is a frontend tool that bundles and builds JavaScript applications, including React. There are other options available depending to build and host React applications depending on what you need, such as Next.js.
Vite is versatile and supports many other frameworks and libraries, including plain HTML and CSS with very little configuration.
Why React?
If you play around with the demo, you will find it returns a blank page when clicking the "Create ticket" button.
In plain HTML and CSS applications, to submit a form you need to host a server and right now, there is no server to accept the form inputs -- but you don't need one!
Using React, you can handle the ticket creation in the browser with JavaScript, as well provide a richer interactive experience -- all without the need for a server.
In a real application, there may be an API or server to send data to but in this lab, you'll just be focused on what you call the "frontend", that is the client-side JavaScript code with React.
Go to the next step to start the migration process!
-
Challenge
Introducing JSX
Introducing JSX
To migrate your application to React, you can start with the HTML structure.
In React, you can write HTML-like syntax using a special language called JSX.
JSX is declarative just like HTML but it's also different in several important ways.
It's easier to show you what JSX looks like than to explain it, so let's get started. Referencing the
index.jsx
file didn't result in any changes with the web app since it was blank, but we're only just getting started.JSX vs. JS Files
First things first: why the
.jsx
extension? Technically, depending on your build tooling, you may be able to use a.js
extension but as a convention, React files containing JSX use the.jsx
file extension. In this case, you want to be clear that you're going to be including JSX markup.Speaking of, why don't you create your first JSX element? It probably felt like you were writing plain old HTML, right?
That's by design -- JSX allows you to write HTML syntax right next to your JavaScript code, and then the JSX gets transformed into... something else. What exactly?
Anatomy of JSX
In the Web Browser tab, you can open the developer console by clicking the "Open in New Window" icon, then hitting F12 to open the browser developer tools. If you look at the console output, you would see something like this:
$$typeof: Symbol(react.element) key: null props: {children: 'Hello World!'} ref: null type: "p" _owner: null _store: {validated: false} _self: undefined _source: {fileName: '/home/ps-user/workspace/index.jsx', lineNumber: 1, columnNumber: 21} [[Prototype]]: Object
This is the anatomy of JSX -- at runtime, the expression you wrote became a JavaScript object with the properties above. More specifically, it is a JSX element.
A JSX element is structurally similar to an HTML element -- it has a tag (
type
), it has attributes (props
), and it can contain other JSX elements (props.children
).Mythbusting: JSX is React
JSX is separate from React itself -- it is its own markup language, which can be used by other frameworks or libraries besides React. However, you may notice the
$$typeof
value referencesreact.element
. This is because JSX needs to be declared with a renderer and in your case, that happens to be React.Rendering JSX
The JSX element you created is living on its own, not attached to your webpage. In other words, it's only been declared but it isn't being rendered anywhere.
Using React, you can render the JSX to the webpage.
-
Challenge
Migrating HTML to JSX
Migrating HTML to JSX
To migrate your HTML application to React, you need to rewrite the HTML in JSX and then render it using React.
Anatomy of a React App
You'll need two key ingredients to render a React app:
- A target DOM element to render within (the "root")
- JSX to render
In the previous step, you already took care of creating some JSX to render initially.
Now you'll need to create a parent HTML element that will "house" your React app. ## Creating a Root
Next, you need to tell React to use this
root
element as the container (or "root") to render into.This is a two-step process:
- Create a React "root" (our container)
- Render JSX into the root
Let's do that now.
Why does React need a target DOM element?
React requires a DOM element to render into. It could be the
body
element of your webpage but by convention, it's usually a separate<div>
element.That element essentially "houses" the React application. That means you can opt to use React only for specific parts of your webpage -- not the whole thing.
You can, for example, call
createRoot()
multiple times on a single page to create several separate React applications (multiple "roots"). In that case, you might pass different target DOM elements. This use case isn't common but you might see it on "hybrid" server-side web applications or when migrating from another framework to React.In the Web Browser tab, check out your handiwork!
At the bottom of the form, you should now see a "Hello World!" message.
Congratulations, you've made a React application!
But hold on -- don't you still have HTML in the
index.html
file? Yes, React applications can live side-by-side with "plain" HTML. What you just did is create aroot
element that will "house" your React app.Go ahead and migrate the HTML into your React app now. ## JSX is not HTML
If you are watching the Web Browser tab or the Terminal, you will notice that you just broke your web app!
This is because even though JSX looks like HTML structurally, it is not HTML and can't always be copy-pasted verbatim.
Let's fix the issues.
-
Challenge
Fixing Issues with JSX
Fixing Issues with JSX
The first error you're seeing is this:
Adjacent JSX elements must be wrapped in an enclosing tag.
Wrapping Element
This is one of the rules of JSX, where if you have multiple adjacent elements like this:
<p>Hello</p> <p>World</p>
They must be enclosed with a wrapping element:
<div> <p>Hello</p> <p>World</p> </div> ``` ## Closing Tags The next error is: > Expected corresponding JSX closing tag for `<input>`. In plain HTML, you can leave elements "open" without a closing tag: ```html <input type="text" name="username">
However, in JSX, you must close all tags either with a "self-closing" tag syntax (
/>
):<input type="text" name="username" />
Or, a full closing tag:
<input type="text" name="username"></input>
You can use the self-closing syntax in all cases where there are no children elements, like for
<input>
elements. ## JSX Props vs. HTML AttributesAt this point, the Web Browser should be showing the application again.
info> Still seeing a blank page? Click the Refresh button next to the address bar.
That means everything's fixed... right?
But if you check the developer console, you'll actually see two similar-looking warnings:
Warning: Invalid DOM property
class
. Did you meanclassName
?Warning: Invalid DOM property
for
. Did you meanhtmlFor
?While the app is rendering properly, the JSX is still technically invalid.
This is because not every attribute from HTML is directly supported verbatim in JSX. In JSX, these are called "props" (as opposed to "attributes") and when you write HTML tags in JSX, they accept the JavaScript DOM attributes.
This means
class
becomesclassName
andfor
becomeshtmlFor
as those are the appropriate JavaScript DOM attributes.How do you know which HTML attributes are valid?
For those new to React, it can be confusing when HTML attributes are not always the same for JSX elements. Migrating `class` to `className` is one of the first obstacles you have to work through, for example.
A good reference is the MDN documentation on the properties of an Element and HTMLElement.
The interesting part is that you've only been dealing with JSX and have not actually created any React components yet.
How do React components compare to plain JSX?
-
Challenge
Introducing React Components
Introducing React Components
Since JSX is independent of React, you can build an entire React application with plain JSX -- but this wouldn't be the best idea because JSX isn't dynamic. Once declared, JSX remains static. React components help make JSX dynamic and react to user interactions.
Anatomy of a React Component
Earlier, you declared a constant with a JSX value, like this:
export const html = <p>Hello World</p>
A React component is essentially a function that returns JSX. The simplest component you can make is transforming the
html
constant into a function that returns the exact same JSX value.Let's make an
<App />
component. ## Components Are... Functions?If you are watching the Web Browser or Terminal tabs, this change has broken the app (again!).
Why?
The
render
method accepts JSX elements and when you passedhtml
to therender
function, you were passing a JSX element.Now, what you've created is technically called a React functional component. It's a pure JavaScript function.
So when you pass
App
by itself, like this:root.render(App);
You are passing a reference to a function declaration.
In other words, you created a function that returns JSX but you're not actually invoking the functional component so that it returns the JSX.
So, how do you invoke a React functional component? There are two ways.
The first is by using React's
createElement
API. -
Challenge
Creating React Components
Creating React Components
Recall earlier that when you inspected the value of the
html
JSX element, it had a$$typeof
ofSymbol(react.element)
.This is because behind-the-scenes, the JSX syntax is translated to pure JavaScript function calls.
You can imagine that the angle brackets are replaced with a function call, like this:
// The JSX: <p>Hello World!</p> // Becomes: createElement('p', 'Hello World!');
In a React application, that function is
createElement
and it is configured for you by default when creating new React apps with popular tools. But you can call it manually, so let's try it out. The app is working again!As you can probably guess, creating React components with
createElement
manually is the hard way. Imagine what it would look like to render a tree of components:createElement('ul', null, createElement('li', null, 'List item 1'); createElement('li', null, 'List item 2'); );
It would be very verbose, wouldn't it? JSX was created to make this easier. All JSX really does is transform HTML-like syntax to JavaScript function calls like this.
Why can't I just call `App()`?
If
App
is "just" a function, why can't you just invoke it? Go ahead and try to invoke theApp
function, like this:root.render(App());
It will work but this is discouraged. That's because JSX is designed to be declarative, and make passing parameters more readable. Plus, directly invoking the function may bypass React's lifecycle handling and state management. It only works in this minimal example because we're not taking advantage of any React features yet.
JSX Elements vs. React Components
Instead of using the
createElement
API directly, you can use declarative JSX markup instead which is the idiomatic way of writing React apps.The JSX markup and usage for components works exactly the same way as regular HTML tags, by using angle-bracket syntax and closing tags:
<Header /> <Main> <p>Hello World!</p> </Main>
There's only one rule when it comes to creating React components with JSX: the component name must begin with a capital letter (like
App
).This is how React differentiates between React components and regular JSX elements. A
<p>
tag is a JSX element (of type"p"
), whereas<App />
is treated as a React component. The app is still working -- because this is equivalent to manually callingcreateElement
. -
Challenge
Extracting JSX Into Components
Extracting JSX Into Components
Since components are functions that return JSX, it means you can "collapse" whole trees of JSX into a single component.
Try it with the
<header>
subtree. Doesn't the JSX look cleaner and less verbose already? The<App />
component now looks more focused with the header extracted.Children Components
You may have wondered why the previous
createElement
example was nested like this:createElement('ul', null, createElement('li', null, 'List item 1'); createElement('li', null, 'List item 2'); );
As you probably know, HTML (and by extension, JSX) is a hierarchy of elements:
<ul> <li>List item 1</li> <li>List item 2</li> </ul>
The
<ul>
tag is the parent of each<li>
tag. The third argument tocreateElement
takes thechildren
of the element to create a component hierarchy structure like this.In the example above, the first call to
createElement
is passed an array of elements as the third argument, which will become its children.These children are passed to the React component, if the component has any.
JSX Substitution
In JSX, you can "inject" JavaScript between markup with open and closing curly braces. Take this
Greeting
component for example:const Greeting = () => { const greeting = "Hello"; const name = "Pluralsight"; return ( <p>{greeting}, {name}!</p> ); } // Renders: <p>Hello, Pluralsight!</p>
Any valid JavaScript expression is allowed within JSX and it's extremely powerful.
Using substitution, you can place the
children
value anywhere in the rendered JSX tree and the children will be "slotted" in.You can access it as the
children
property on the first argument passed to a functional component (itsprops
), like this:const Main = (props) => ( <main> {props.children} </main> );
This yet another way to "encapsulate" entire subtrees of JSX with React components, which will become a powerful pattern as you build your React apps.
Let's try it by creating this same
Main
component. One of the benefits of wrapping thechildren
of a React component is reusability. For example, you can now reuse the<Main>
component with any children, effectively allowing you to encapsulate styling.Why don't you do the same thing with each of the form groups within the
<form>
to make a reusable<FormGroup>
component? At this point, you've reduced some repetition and created multiple components that encapsulate each of the form fields.You can now take this a step further and encapsulate logic with components.
-
Challenge
Using JavaScript in Components
Using JavaScript in Components
Where React really shines is in using components to encapsulate logic and behavior. Since a React component is "just JavaScript," that means you can use JavaScript code in components to create dynamic UIs.
Focus on the product dropdown. It lists the different Globomantics products that the ticket relates to. In a real-world application, don't you think this list of products might actually come from a database or API?
You don't have an API in this application, but you can still extract this product list into a JavaScript data structure and turn the
<select>
options from a static list into a dynamic list.You can use a plain JavaScript array, then use JSX substitution syntax along with the native Array
map()
function to iterate over each array item. The return value of themap
operation will be... what exactly? JSX!The first step is to encapsulate this new logic into a React component for the product field. The next step is to extract the list of product names into a JavaScript array within the component function body. By substituting the array within the JSX under the
<select>
element, what would you expect to see in the Web Browser tab?Perhaps a dropdown of product names?
But instead, what you'll see is something very strange... the select dropdown is empty. What's going on there?
When you substitute a variable in JSX, it must be either a
string
, a JSX element, an array of JSX elements, or a React component. Instead, you substituted an array of string values, which aren't supported under an HTML<select>
element. They need to be<option>
elements.Inspecting raw HTML rendering
In the Web Browser tab, if you open the developer tools and inspect the
<select>
element, you would see the following HTML:<select name="product">GloboCMSGloboFinance+GloboHRGloboIT Portal</select>
React is effectively rendering each array value using
toString()
. This is invalid HTML, hence why the browser renders an empty select dropdown.To fix this, you need to map the array values from a
string
value to a JSX element. The nativeArray.map
function accepts a callback that takes the original array value and can return a new value that will be mapped into a new array, which is perfect for rendering lists in React.You will do this where you originally substituted the
products
array within the JSX body and return<option>
JSX elements for each array value. Now if you refresh the Web Browser tab, and click the Product dropdown, the list of products is displayed!But we're not quite done yet.
Array Keys
In the browser Developer Tools, the console is emitting some warnings like this:
Warning: Missing "key" prop on array children
React needs to be able to keep track of individual array items being rendered if the list changes over time. To track items internally, React requires all top-level mapped JSX elements to have a
key
prop set to some unique value for that array item.In your case, the product name is unique so it can also be used as the key for each
<option>
element. In other cases, you can pass a number value, pass an ID value, or construct a dynamic string from properties of the array value that will be unique. After reloading with the changes, the dropdown is working and you have a valid React application.Powered by JavaScript
When you look at the JSX for rendering this dynamic product list, it probably feels familiar to writing HTML but by now you understand that it's not HTML, it's JavaScript. Using JavaScript allows you to write highly dynamic applications.
By extracting the product list, you made your app more maintainable, and open to extension. In the future, you could pull that list of products from an API or database.
-
Challenge
Recap and What's Next
You now have a solid understanding of how React works and how writing JSX differs from writing HTML.
Recap
- JSX is separate from React -- it is a markup language similar to HTML that gets transformed into pure JavaScript function calls
- A key difference of JSX from HTML is how it uses JavaScript DOM attribute names instead of HTML attribute names (like
className
instead ofclass
) - JSX supports substituting expressions using curly-brace
{variable}
syntax - When used with React, JSX elements are transformed to build component trees with the
createElement
API - React functional components are invoked in JSX using the same HTML-like tag syntax (e.g.
<App />
) - Children subtrees are passed as the
children
prop to components and can be "slotted" into JSX using substitution syntax - You can encapsulate behavior with components and write JavaScript code to dynamically render JSX
- React uses the
key
prop to track changes to array children when rendering
What's Next?
You probably have so many other questions, like...
- What are
props
exactly? - How do you pass data to components?
- How do you read the form input data?
- How can you handle submitting a ticket?
That's what you'll explore in the next guided lab in this series when you learn more about Props and State.
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.