This article walks you through how to create a simple React app using TypeScript and a Material Design framework.

Prerequisites 

This article assumes the following:

  • You are editing with Visual Code 
  • You have nodejs, npm and npx installed
  • You are testing using the Chrome browser
  • When I say "app" I am referring to your code running in a browser

This article was tested on a Mac and may or may not need a few steps adjusted for working on Windows or Linux.

Step 1. Install create-react-app

Make sure that you have the latest version of the create-react-app by uninstalling any previous version first.

Note that the $ indicates a terminal window prompt and should not be included in the command:

$ sudo npm uninstall -g create-react-app

Now install the latest version:

$ sudo npm install -g create-react-app

Step 2. Run create-react-app for TypeScript

Use the create-react-app to generate a project to start from.

  • Open up a terminal window
  • Change to a root project folder (example: cd ~/projects)
$ npx create-react-app material-101 --template typescript
$ cd material-101
$ code .
$ npm start

Step 3. Edit the title

To change the title that appears in the browser tab, do the following:

  • Edit public/index.html
  • Replace the content of the title tag with “Material 101
  • Save the file
  • Toggle back to the browser
  • Verify that the title in the tab has been updated (if not, refresh the browser)

Open up the terminal window panel inside of Visual Code:

  • On a Mac press: Control ~

Step 4. Install a Material Design framework

React by itself does not have everything that you need to create apps using Material Design. Here are the steps for adding a framework to your project that we will use below:

In the terminal panel:

$ npm install --save @mui/material @mui/icons-material
$ npm install --save @emotion/react @emotion/styled

Step 5. Add a TSX stylesheet

The create-react-app app installed a regular CSS stylesheet. But to work with the framework you need to create a second TSX (TypeScript + React) stylesheet. The styles are not defined using a CSS format, but instead a TSX format.

  • Create a new file in the src folder: src/AppStyles.tsx
  • Replace the contents with the code below and save the file:
export const AppStyles: any = {
    cardStyle: {
        width: '400px',
        margin: 'auto',
        marginTop: 20,
        textAlign: 'center',
        display: 'block',
    },
    logoStyle: { 
        marginTop: '20px', 
        marginBottom: '20px', 
        padding: '10px', 
        border: '1px solid black', 
        borderRadius: '50%' 
    }
}

Even though it looks a lot like CSS, notice the difference in how many values are contained within string quotes, etc. It is formatted using the JSON-like object syntax to compile as TypeScript code. This is for formatting the Material Design framework components.

Step 6. Create a card

In Material Design you can build your UI around the concept of cards. For this example the whole app will be within a card that is centered in the browser window.

  • Edit src/App.tsx
  • Replace the contents of the App function with the code below:
function App() {
  return (
    <Card style={AppStyles.cardStyle}>
        <CardContent>
          <SmartToy style={AppStyles.logoStyle} fontSize="large" />
          <Typography gutterBottom variant="h5" component="h2">
            Material 101
          </Typography>
        </CardContent>
     </Card>
  );
}

export default App;
  • You should see a series of underlined errors
  • Wave your mouse over each error and select the Quick Fix option
  • Usually pick the first option
  • You may find that not all errors can be corrected this way
  • If your editor is not setup for this I will provide instructions for doing things manually below

The top of your file should now look like this. If it does not, manually edit it to look like this:

import React from 'react';
import logo from './logo.svg';
import './App.css';
import { Card, CardContent, Typography } from '@mui/material';
import { SmartToy } from '@mui/icons-material';
import {AppStyles} from './AppStyles';

You can remove the import logo line.

  • Save the file
  • Verify in the browser that you can see the start of your app and that there are no errors
  • If you don't see the card, refresh your browser

Step 7. Add a variable using React Hooks

For this example you will need the latest version of React that supports React Hooks.

  • Add this line above the return statement:
const [userName, setUserName] = useState('');
  • The useState function should show an error
  • Add a Quick Fix which will change the React import line to include it:
import React, { useState } from 'react';

Step 8. Add a change handler

I am going to show you how to create a text edit control to manage entering the user name. But for the form to work you are going to need to first define a function to handle changes as you edit.

  • Add this code below the useState line:
const handleUserNameChange = useCallback((event) => {
    setUserName(event.target.value);
}, []);
  • Add a Quick Fix or manually add useCallback to the import React line at the top of the file which should now look like this:
import React, { useCallback, useState } from 'react';

Step 9. Add second CardContent block

To add a text field I am going to have you put it in another CardContent block. This is a way of organizing your card into smaller chunks and groups. I could also have made it another card which would be a child of the first card and have a different format. But for now I am keeping the design very simple.

  • Right after the first CardContent block, insert this code with a second block into src/App.tsx:
    <CardContent>
       <FormControl style={{ width: '50%' }} >
          <TextField
            id="userName"
            name='userName'
            label="Your name"
            value={userName}
            onChange={handleUserNameChange}
            helperText='Enter your name'
          />
       </FormControl>
    </CardContent>
  • Quick Fix the errors which should update the material import line to look like this:
import { Card, CardContent, FormControl, TextField, Typography } from '@mui/material';
  • The id, name and value fields must all match the name of your variable (userName)
  • The onChange handler should reference your handler function
  • Save the file
  • In the browser make sure that you can type in your name

Step 10. Create card actions

When you create buttons using the framework, the standard is to put them into a CardActions block.

Add the code below right after the last CardContent block:

     <CardActions>
        <Tooltip title="Click to say hello">
          <span>
            <Button color='primary'
              disabled={userName.length === 0}
              variant="outlined"
              onClick={handleClickHello}
              key={1}>
              Say Hello
            </Button>
          </span>
        </Tooltip>
        <Tooltip title="Click to say yo">
          <span>
            <Button color='secondary'
              disabled={userName.length === 0}
              variant="outlined"
              onClick={handleClickYo}
              key={2}>
              Say Yo
            </Button>
          </span>
        </Tooltip>
      </CardActions>

As alway, fix any errors with Quick Fix.

The code wraps two buttons in the framework Tooltip tag. This is how to create a message that appears when the user waves the mouse over each button.

Each buttons disabled property checks the length of userName. If the length is zero, they will be disabled. To enable them, just start typing in a user name.

The reason the buttons are wrapped in spans is a quirk of the framework. The Tooltip requires at least one child component to be enabled (like span) or it logs an error to the browser console.

The variant defines the style of the button. Consult the framework documentation for other variants.

The onClick handlers will be defined below.

Step 11. Add the handler methods

Below the handler method for the name change, add these handlers for the buttons above:

  const handleClickHello = useCallback((event) => {
    alert(`Hello ${userName}!`)
  }, [userName]);

  const handleClickYo = useCallback((event) => {
    alert(`Yo ${userName}!`)
  }, [userName]);

It is important that you put userName in the brackets at the end of each callback. Otherwise the username will be blank in the alert box.

When you are done, make sure that you have saved all files and test your work!

Step 12. Test your work!

  • Refresh the browser
  • Notice that the buttons are gray and disabled until you enter some text
  • Enter some text and click a button
  • Make sure that the name you entered comes up in the alert box
  • Verify that the message matches the button you clicked

Step 13. Deploy a build

If you look at the package.json file you will see this script:

"build": "react-scripts build",

From a command line run it like this:

$ npm run build

That will generate a new folder called build in the root of your project.

If you are familiar with static hosting sites like surge.sh or Netlify you can use their services to publish your build folder to temporary test sites under their domains.

After you ran the build command it also provided instructions for test serving the files locally. I’ve modified the command to use sudo to avoid any rights issue installing an npm package globally:

$ sudo npm install -g serve
$ serve -s build

When you run the serve command it should tell you what port it is using. In my case the port was 5000, so to test the served build I browsed to:

  • http://localhost:5000/

Where to find the source

You can find the source for the app featured in this article on GitHub:

Embedded Example

You can see the code in action using this embedded example:

Conclusion

In this article I walked you through how to get started using Material Design to build a React app using TypeScript.

You learned how to use a framework to build a simple card-based IU using React Hooks.

To learn more, read the documentation on the framework (link below) and experiment with the other components that it provides.

Be sure to also read the Material Design documentation to understand how to use the framework more effectively.

References