Module 4 - Advanced Styling Techniques

Create React App

Technically, you could build an entire React app with a single HTML file and some JavaScript. But as you already know, developing in React is more complex than writing vanilla JavaScript. You will have to do a lot of configuration upfront and manage tasks like setting up a compiler to convert JSX to JS. This approach is definitely not scalable.

A bootstrapping tool will make the whole process so much easier. "Bootstrapping" describes generating a basic application that you can build on. Using a bootstrapping tool allows you to concentrate on individual tasks and components instead of configuring a new app from scratch. As long as you correctly import, export, and link the modules, your app will be easily maintained and upgraded, and you can kickstart your React project with ease and confidence!

These initialization tools will create the complete folder/files "boilerplate" structure in your local environment, along with compilers and bundle generators. You will be using your local code editor and development web server, and when ready, build your app into production with a few clicks.

Alternatively, you could use an online code editor (e.g., Replit) for quick prototyping. But in most cases, at some point, you will benefit from having a local environment setup for development.

So far, you have been using Bloomtech's React initialization tool, and this is the preferred approach during your learning journey since we have complete control of the tool: versioning, updates, future capabilities, bug fixes, etc. By the way, that's why the practices always refer to a specific version of the tool - to guarantee the code will not break even if the tool is upgraded and loses backward compatibility.

But then again, our tool was specifically designed for this training program. When working with real-world projects, you may use another tool, often specified by the company/client. In other cases, you may need to maintain existing apps created by a specific third-party tool.

Let's learn how to use some of the most popular bootstrapping packages!

Bootstrapping a React app

For a long time, the create-react-app has been the standard for initializing React apps and has been primarily used by projects worldwide. Contrary to popular belief, this tool is not maintained by the original React developers, but it was the official recommendation on React's website for a long time.

Over the years, other tools have evolved as strong competitors in the Industry by incorporating additional features. Nevertheless, given its simplicity and historical popularity, you will learn how to use the create-react-app tool, which works great for many React applications. Later, you will be presented with some of the other options available.

How to Build It

Create React App

Here's the official website for CRA. Some of the key points listed by the developers are:

  • Only one dependency
  • Get started in seconds
  • Easy to maintain

Assuming you have NodeJS and npm properly installed and updated, the installation is as easy as:

npx create-react-app my-app
cd my-app
npm start

Where my-app is the name of the root project directory. The code above will create the project tree and launch the development server running a sample app at port 3000. From this point, you can open the project directory in your local editor and make real-time updates to App.js. The project tree will look similar to this:

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── serviceWorker.js
    └── setupTests.js

Pro Tip: for the project to build, these files must exist with exact filenames: public/index.html is the page template; src/index.js is the JavaScript entry point.

Notice how the tool also creates files and scripts for testing. You will learn how to do testing in React at a later Core Competency.

To update the tool and its development dependencies when a new version is released, you should use the following:

npm install react-scripts@latest

Finally, when you're ready to deploy to production, run the following command to create a minified bundle that can be uploaded to your remote web server:

npm run build

Take some time to inspect the contents of index.html and index.js. Notice how they "connect" the root DOM element to the App component and how essential modules are exported and imported.

Alternative Tools

As of today (July 2023), on the official React website, you will find the following:

To build an entire app with React, we recommend a full-stack React framework like Next.js or Remix.

A framework is a collection of tools designed for streamlined development. While create-react-app can also be considered a framework, NextJS and Remix offer extra capabilities that might interest some projects.

Keep in mind that as scaffolding tools get more versatile and powerful, the more you will have to study, practice and risk running into issues. The beauty of CRA lies in its simplicity and ease of use!

NextJS

NextJS has been designed to be a full-stack web development framework tightly aligned with React. You will have access to tools like Dynamic HTML Streaming, React Server Components, Data Fetching, CSS Styling, and Route Handlers. But you won't need to use many of these capabilities until you start working with complex applications and full-stack development.

Installing NextJS and firing up the local development server is also straightforward:

npx create-next-app@latest
npm run dev

Once again, take some time to inspect the project tree and recognize all the key files and how they are linked. Refer to Next.js website for documentation and tutorials.

Remix

The Remix framework is all about creating great looking User Interfaces. Remix has its own syntax and exposes tools to create routes (pages, URIs) easily and styling through templates. Similarly, you would initialize a project and spin up the local server with the following:

npx create-remix@latest --template remix-run/template my-app
npm run dev

Check out all the templates and example tutorials at the Remix website.

Conclusion

Developing with React can be much easier when you use a bootstrapping tool to initialize your project. In fact, as we start to incorporate AI tools into development, many other time-consuming tasks will become automated so that you, the developer, can really concentrate on what's important: creativity, performance, efficiency, and maintainability.

Throughout this unit, you will generally use Bloomtech's bootstrapping tool.

As you progress in your career and start maintaining and creating apps for different companies and clients, you will most certainly use more than a few bootstrapping tools. You may specialize in one of them to gain agility and confidence. Once you learn the fundamentals of any initialization tool, you should be comfortable migrating to another!

Next, you will learn how to style your React components and bring your application to a new level of user experience!

Styling in React

In this Core Competency, you will explore two popular approaches for styling React applications: Reactstrap and Styled Components.

Reactstrap exports a rich collection of pre-built React components. "Elements" such as Button, Card, Carousel, and Spinner can be easily imported by your components, allowing you to create responsive and visually appealing user interfaces. As a turn-key solution for styling components, Reactstrap is perfectly suitable for many types of applications. Yet, sometimes you must design your collection of styles and have complete control of the styling components.

This is where Styled Components is your friend - a powerful module that offers a dynamic approach to styling, allowing for the creation of reusable and highly customizable styles.

When you finish these readings, you will have the knowledge and tools to craft stunning and engaging user interfaces in your React applications. Let's go!

Styling with reactstrap

This lesson is about getting you up and running with Reactstrap, the de-facto styling library for React Components. As mentioned, Reactstrap exposes a rich collection of pre-built "elements" as React components that can be imported into your app.

Reactstrap relies on the popular Bootstrap CSS/library. Bootstrap must be manually installed and imported into your application as a dependency.

To install Reactstrap, jump into your project directory and:

npm install reactstrap

As for Bootstrap, you can either install the module and import it in JS like this:

npm install bootstrap

And then inside your index.js file:

import 'bootstrap/dist/css/bootstrap.min.css';

Or import the CSS file right from index.html, by including this code inside the <head> tag:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css"
/>

When using the latter approach, make sure to visit the Reactstrap installation page to confirm the recommended/latest version of Bootstrap.

How to Build It

Let's revisit the Random Picture. Before anything else, go into the project directory and install Reactstrap per the instructions above. Then edit the App.js file to test some styled-components:

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import { Alert } from 'reactstrap';

export default function App() {
  const [pic, setPic] = useState("");
  const [info, setInfo] = useState("");
  useEffect( () => {
    axios
      .get("http://localhost:9009/api/pics/random")
      .then(res => {
        setPic(res.data.file);
        setInfo(res.data.detail);
      })
      .catch(err => console.log(err));
  }, []);

  return (
    <div className="App">
      <h1>This is a nice random picture!</h1>
      <img src={pic} height="300px" alt="a random picture" />
      <Alert>{info}</Alert>
    </div>
  );
}

And just like that, you get a good-looking message box in your UI!

Now, instead of clicking on the browser's refresh button to get a new picture, you can add a styled button and assign a callback:

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import { Alert, Button } from 'reactstrap';

export default function App() {
  const [pic, setPic] = useState("");
  const [info, setInfo] = useState("");
  const refreshPage = () => {
    window.location.reload()
  };
  useEffect( () => {
    axios
      .get("http://localhost:9009/api/pics/random")
      .then(res => {
        setPic(res.data.file);
        setInfo(res.data.detail);
      })
      .catch(err => console.log(err));
  }, []);

  return (
    <div className="App">
      <h1>This is a nice random picture!</h1>
      <img src={pic} height="300px" alt="a random picture" />
      <Alert>{info}</Alert>
      <Button color="success" size="lg" onClick={refreshPage}>RANDOM PICTURE</Button>
    </div>
  );
}

You may have noticed that you can customize some styles by changing the props. Very nice!

For a complete list of elements and available styles/props, please take a look at the official documentation. For instance, this is the Button page. Notice how onClick is one of the available props and uses the same syntax as the regular React <button>.

Take some time to experiment with these interesting elements:

  • Card: a flexible and extensible content container for pictures, text, links, etc.
  • Carousel: a slideshow component for cycling through images.
  • Spinner: the famous spinning wheel you can use to tell the user that the app is waiting for remote data!

Styling with styled components

The previous approach to styling with Reactstrap is very "Reactish" and should be really easy to use for any dev with some React experience. After all, you are dealing with components, imports, and the same React syntax.

Styled Components, on the other hand, is a library for writing CSS-like code inside your components. Like JSX is a wrapper for writing HTML in JS, Styled Components will allow you to write CSS in JS.

The whole point here is to encapsulate everything about the component in the same file! By working on individual components, you can entirely focus on a single section/functionality of the page without going back and forth between HTML, CSS, and JS files.

Inside your project folder, you will install Styled Components with npm, as usual:

npm install styled-components

How to Build It

Once again, go to your Random Image app, and edit the App component back to:

import React, {useState, useEffect} from 'react';
import axios from 'axios';

export default function App() {
  const [pic, setPic] = useState("");
  const [info, setInfo] = useState("");
  const refreshPage = () => {
    window.location.reload();
  };
  useEffect( () => {
    axios
      .get("http://localhost:9009/api/pics/random")
      .then(res => {
        setPic(res.data.file);
        setInfo(res.data.detail);
      })
      .catch(err => console.log(err));
  }, []);

  return (
    <div>
      <h1>This is a nice random picture!</h1>
      <img src={pic} height="300px" alt="a random picture" />
      <h3>{info}</h3>
      <button color="success" size="lg" onClick={refreshPage}>RANDOM PICTURE</button>
    </div>
  );
}

You are back to using regular JSX and the default <button>. Please ensure the app works in the browser, and check the console for any warnings or errors.

Now import styled-components and create a custom Button:

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import styled from 'styled-components';
const Button = styled.button``;

export default function App() {
  const [pic, setPic] = useState("");
  const [info, setInfo] = useState("");
  const refreshPage = () => {
    window.location.reload();
  };
  useEffect( () => {
    axios
      .get("http://localhost:9009/api/pics/random")
      .then(res => {
        setPic(res.data.file);
        setInfo(res.data.detail);
      })
      .catch(err => console.log(err));
  }, []);

  return (
    <div>
      <h1>This is a nice random picture!</h1>
      <img src={pic} height="300px" alt="a random picture" />
      <h3>{info}</h3>
      <Button onClick={refreshPage}>RANDOM PICTURE</Button>
    </div>
  );
}

Let's study the code above. First, we added two lines outside of the function:

import styled from 'styled-components';
const Button = styled.button``;

Which are, the actual import and the creation of the Button styled component. Styled components should always be declared outside of the component function.

What about this syntax: const Button = styled.button``;

When you create a Styled Component, you call a method from the default export (styled) and pass a string literal as an argument. You can learn all about string literals here, but in summary, by using back-ticks, you can pass multiple strings to a function, including the result of expressions. In the example above, we create the default component with no arguments.

Next, you have replaced the JSX with the styled component:

<Button onClick={refreshPage}>RANDOM PICTURE</Button>

Now change the styled component declaration to:

const Button = styled.button`
  background: cyan;
  border-radius: 3px;
  border: 2px solid #BF4F74;
  color: #BF4F74;
  margin: 0 1em;
  padding: 0.25em 1em;
`;

Can you see what's happening here!? You can add regular CSS code inside your literal string, which works! The possibilities are now endless.

Try something else: create a new styled component by adding the following:

const WrapperDiv = styled.div`
    width: 80%;
    height: 80%;
    background-color: light-grey;
    padding: 2em;
`;

And substitute the root JSX <div> with <WrapperDiv>:

return (
  <WrapperDiv>
    <h1>This is a nice random picture!</h1>
    <img src={pic} height="300px" alt="a random picture" />
    <h3>{info}</h3>
    <Button onClick={refreshPage}>RANDOM PICTURE</Button>
  </WrapperDiv>
);

And that's how it works! You can basically create new "tags" using this syntax and use them as you would do with regular HTML tags and the class="" attribute. Please refer to the official documentation for all the power available with Styled Components.

While this is cool, it seems too much work for just using CSS code inside JS... Until you realize that there is so much more, you can do by taking advantage of a key feature of React components: props.

Some pictures look better over a dark background. Let's make a few changes:

  • Add state to keep track of "Dark Mode";
  • Create a simple button to change the state;
  • Pass the darkOn value as a prop to WrapperDiv;
  • Calculate/interpolate the background color by using an expression to evaluate the prop value inside the string literal.

Study this final code and imagine the possibilities of using props with Styled Components:

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import styled from 'styled-components';

const Button = styled.button`
  background: cyan;
  border-radius: 3px;
  border: 2px solid #BF4F74;
  color: #BF4F74;
  margin: 0 1em;
  padding: 0.25em 1em;
`;

const WrapperDiv = styled.div`
    width: 80%;
    height: 80%;
    background-color: ${props => props.darkMode ? "dimgrey" : "gainsboro"};
    padding: 2em;
`;

export default function App() {
  const [pic, setPic] = useState("");
  const [info, setInfo] = useState("");
  const [darkOn, setDark] = useState(false);
  const refreshPage = () => {
    window.location.reload();
  };
  useEffect( () => {
    axios
      .get("http://localhost:9009/api/pics/random")
      .then(res => {
        setPic(res.data.file);
        setInfo(res.data.detail);
      })
      .catch(err => console.log(err));
  }, []);

  return (
    <WrapperDiv darkMode={darkOn}>
      <h1>This is a nice random picture!</h1>
      <img src={pic} height="300px" alt="a random picture" />
      <h3>{info}</h3>
      <Button onClick={refreshPage}>RANDOM PICTURE</Button>
      <button onClick={()=>setDark(!darkOn)}>Change Background Color</button>
    </WrapperDiv>
  );
}

Notice how you can choose whatever name for the props. You are using darkMode here, so make sure to use the same name inside the evaluation expression.

String literals allow expressions to be evaluated with the ${} syntax. With Styled Components and props, the expression is always a callback function that receives the props.

With this and much more that you can learn from the styled-components docs, you can move styling into the JS component file, create dynamic reusable components, and even design your style library!

Styling with Styled Components Part A

Styling with Styled Components Part B

Conclusion

Styling is a big part of any application, as appealing user interfaces can make a huge difference in comfort and ease of use.

While there are many ways to implement styles (e.g. CSS, inline HTML, JSX), modules like reactstrap and styled-components are great alternatives for styling in a "React way", giving you the power of component-focused development.

Guided Project

Advanced Styling Techniques Starter Code

Advanced Styling Techniques Solution

Module 4 Project: Advanced Styling

This module project will use the same code you used in Module 3. You will be adding styling to the app.

The module project contains advanced problems that will challenge and stretch your understanding of the module's content. The project has built-in tests for you to check your work, and the solution video is available in case you need help or want to see how we solved each challenge, but remember, there is always more than one way to solve a problem. Before reviewing the solution video, be sure to attempt the project and try solving the challenges yourself.

Instructions

You will use the same repository that you worked on for Module 3 (Side Effects), continuing the project where you left off.

Load the project in your computer and open the README_DAY_TWO.md file in VSCode, where you will find instructions on completing this project.

Submit your completed project to the BloomTech Portal

Solution

Additional Resources