Featured resource
pluralsight tech forecast
2025 Tech Forecast

Which technologies will dominate in 2025? And what skills do you need to keep up?

Check it out
Hamburger Icon
  • Labs icon Lab
  • Core Tech
Labs

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.

Labs

Path Info

Level
Clock icon Beginner
Duration
Clock icon 1h 51m
Published
Clock icon May 08, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. 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 (like index.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!

  2. 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 references react.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.

  3. 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:

    1. A target DOM element to render within (the "root")
    2. 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:

    1. Create a React "root" (our container)
    2. 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.

    ## You Now Have a React App

    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 a root 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.

  4. 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 Attributes

    At 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 mean className?

    Warning: Invalid DOM property for. Did you mean htmlFor?

    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 becomes className and for becomes htmlFor 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.

    You've now successfully completed the migration of a plain HTML webpage to a React application.

    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?

  5. 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 passed html to the render 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.

  6. Challenge

    Creating React Components

    Creating React Components

    Recall earlier that when you inspected the value of the html JSX element, it had a $$typeof of Symbol(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 the App 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 calling createElement.

  7. 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 to createElement takes the children 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 (its props), 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 the children 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.

  8. 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 the map 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 native Array.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.

  9. 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 of class)
    • 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.

Kamran Ayub is a technologist specializing in full-stack web solutions. He's a huge fan of open source and of sharing what he knows.

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.