Technical Writing

The Complete Guide To Component Styling with Chakra-UI in React

2021-03-20

Last year I discovered Chakra UI and have been using it in all my projects since then. In this tutorial, you will ;earning how to use Chakra Ui too by building a simple landing page with Chakra UI components.

Sometime last year, I visited this super helpful GitHub repo containing design resources in search of component libraries. After going to the React UI libraries section, I visited the websites for each of the libraries to see the components that they had, and see how well documented they were. At the end, I eliminated most of the other choices because I wasn't happy with the design system or some limitations they had. I finally had to choose between Chakra UI and Bumbag. I chose to stick with Chakra UI and now, many months later I am still very satisfied with that choice that I made.

The Chakra UI promise

The header on the landing page of chakra UI says "build accessible react app with speed". Ever since I started using Chakra UI, the product has always kept up to its promise.

Some weeks ago, someone met me to create a little app that will be used for a program that will be held on the next day. I agreed to do it because I knew that with Chakra UI, anyone can create a great website in little time. After an hour, I had already created a not so good looking but working prototype to show to the person. It was approved and then I spent a few more hours making the prototype look more awesome. In this tutorial, we will be learning how to use Chakra UI by building a sample app. In this tutorial, you will be building a landing page with Chakra UI for a home rental agency.

Prerequisites

To install ChakraUI's official create-react-app template, you

  • Install create-react-app if you already haven't by running npm install -g create-react-app in a terminal
  • Create a react app from the Chakra UI template by running npx create-react-app my-app --template @chakra-ui
  • Start the development server by running cd my-app and yarn start
  • Open your browser to http://localhost:3000

Now you should be greeted by a Green Spinning chakra UI logo

The first thing we are to do is to remove the default page with a blank page. Open the file at my-app/src/app.js and edit it to look as follows instead.

import React from 'react'
import { ChakraProvider, theme } from '@chakra-ui/react'

function App() {
  return <ChakraProvider theme={theme}></ChakraProvider>
}

export default App

The development server will rebuild our app and the page will refresh automatically. You should now have a blank page. We will now create our own layout here. We will only import a component from the library when we need it to render a component. This means that whenever you see import { ..., Component } from '@chakra-ui/react';, you will need to import the new components that we add to the top.

Creating the unstyled Big Header

Import the Heading, and Text components from Chakra UI. After importing Heading and Text, the import statement for chakra-ui should be similar to this.

import { ChakraProvider, theme, Heading, Text } from '@chakra-ui/react'

Now you have imported the components needed, edit the App function in App.js to be like this.

function App() {
  return (
    <ChakraProvider theme={theme}>
      <Heading as="h1">Find a Home Away from Home</Heading>
      <Text>
        We are the world's leading home rental service with over 10 thousand home owners matched
        with customers annually
      </Text>
      <Text>Get Started</Text>
    </ChakraProvider>
  )
}

When the page refreshes, you will see the text displayed on the page. However, the text that is rendered will be unstyled. You added a Heading component containing the most important text and then two Text components that are used for the subtitle and the call to action button. If you look at the Heading component, you will notice that an as prop is added. This prop decides which HTML tag that the heading will be rendered as. This is because the Heading component renders a h2 by default. To adjust the component to render a h1 or h5 you will pass the tag you need to the as prop. In the next step, we will add some style to the page to make it more visually appealing to our end users.

Adding styles in Chakra UI

Now we're in the fun part. This is the place where the beauty of Chakra UI lies. In chakra UI, styles are added to components through style props. For example, to change the font size of a component like this, <Heading>Find a Home Away from Home</Heading>, you will set the fontSize prop to a value like 50px, so the component will be <Heading fontSize="50px">Find a Home Away from Home</Heading> instead. Here is a list of the most important styles and the props that we can use to modify the value of those styles.

  • font-size: fontSize
  • font-weight: fontWeight
  • text-align - textAlign
  • width - w, width
  • height - h, height
  • min-width - minW, minWidth
  • background - bg, background
  • color - color

Here is a full list of ChakraUI style props.

One other great feature Chakra UI has is that it comes with an already made set of values that you can pass to style props. Instead of setting the fontSize of a Heading to 60px, you can set it to something like 4xl, 2xl or sm which makes a lot more sense. For example, to change the font size of the heading, you can change the component to <Heading fontSize="6xl">Find a Home Away from Home</Heading> or <Heading fontSize="sm">Find a Home Away from Home</Heading>.

To add a red color to the heading, we can do <Heading color="red">Find a Home Away from Home</Heading>. Chakra UI, however makes things a lot better. It comes with a default palette that exports different shades of colors. Instead of setting color to just red, we can use a light version of red by setting color to red.100 or a darker color by setting it to red.700. Multiples of 100 between 100 and 700 and 50 work too. There is a page in the documentation dedicated to listing these special style values.

In the following code block, we will add styles to the header. Start by importing the Box component from chakra-ui and then change the component that is returned by the App function to

<ChakraProvider theme={theme}>
  <Box maxW="2xl" m="0 auto">
    <Heading as="h1" textAlign="center" fontSize="7xl" mt="100px">
      Find a Home Away from Home
    </Heading>
    <Text fontSize="xl" textAlign="center" mt="30px">
      We are the world's leading home rental service with over 10 thousand home owners matched with
      customers annually
    </Text>
    <Text
      w="fit-content"
      p="4"
      px="50px"
      bg="blue.300"
      borderRadius="10px"
      m="0 auto"
      mt="8"
      fontWeight="bold"
      color="white"
      fontSize="xl"
    >
      Get Started
    </Text>
  </Box>
</ChakraProvider>

When you reload the page, the page should look a lot better. We did this by adjusting the font sizes of the different texts, adding margins between them and by adding a background color to our call to action with bg="blue.300".

Note: The call to action that is displayed on the homepage should normally be a link to a different page, but we made it to just be plain text. This is intentional in our tutorial. You will want to change this to the chakra ui link component instead as everything pairs up nicely.

Turning our components to functions - cleaning up our code

In order to make it easier to edit a component individually, react components are moved to and exported from a separate file and are imported wherever they are needed. This idea is illustrated in great detail in this great article. However, we won't separate our components into different files, but rather we will separate them into various functions and then return them wherever they are needed in the App function.

Edit App.js to look like this instead.

import React from 'react'
import { ChakraProvider, theme, Heading, Text, Box } from '@chakra-ui/react'

function TopHeading() {
  return (
    <Box maxW="2xl" m="0 auto">
      <Heading as="h1" textAlign="center" fontSize="7xl" mt="100px">
        Find a Home Away from Home
      </Heading>
      <Text fontSize="xl" textAlign="center" mt="30px">
        We are the world's leading home rental service with over 10 thousand home owners matched
        with customers annually
      </Text>
      <Text
        w="fit-content"
        p="4"
        px="50px"
        bg="blue.300"
        borderRadius="10px"
        m="0 auto"
        mt="8"
        fontWeight="bold"
        color="white"
        fontSize="xl"
      >
        Get Started
      </Text>
    </Box>
  )
}

function App() {
  return (
    <ChakraProvider theme={theme}>
      <TopHeading />
    </ChakraProvider>
  )
}

export default App

What you just did was that you created TopHeading function that returns the heading that we just created and then we add it to our page by adding to the App function. This will make development a lot easier. This is because for every subsequent component we make, we will just create a function that returns what we need and add it to the App function where it is needed.

Creating a section for top destinations

As this is a landing page for a rental service, you will possibly want to show the user some cards containing information on some top destinations where our services are available. To do this, we will create a TopDestinations function that contains the JSX for this section and add it to app.js

Create a TopDestinations function above the app function App in app.js

function TopDestinations() {
  return (
    <Text fontSize="5xl" fontWeight="bold" textAlign="center" mt="100px" mb="30px">
      Top Destinations
    </Text>
  )
}

When you save, you will notice that nothing extra is rendered on our page. This is because it is the App function that is rendered and the TopDestinations component has not yet been added to it. To do this, you just have to add <TopDestinations /> below TopHeading in App. The function should look like this now.

function App() {
  return (
    <ChakraProvider theme={theme}>
      <TopHeading />
      <TopDestinations />
    </ChakraProvider>
  )
}

When your browser refreshes after rebuilding the bundle, you will notice that only a title is rendered. The next thing we want to do is to create the cards for the destinations. In TopDestinations, we have the title. We are now going to add the cards to that section.

Creating a card in Chakra UI

We will create a Destination function that will return this card. Two of these cards will then be added to the TopDestinations section. While creating the destination function, we will be using four new components from chakra-ui so you will have to import them to use them. Import Badge, Flex, Spacer and Button from chakra-ui. After this, define the following Destination function.

function Destination() {
  return (
    <Box m="8" border="1px solid" borderColor="gray.400" w="300px" borderRadius="lg">
      <Box w="100%" h="200px" bg="gray.100" borderTopRadius="lg"></Box>
      <Box p="4">
        <Badge fontSize="0.8em" colorScheme="red">
          Popular
        </Badge>
        <Text fontSize="2xl" fontWeight="bold">
          Brawhala
        </Text>
        <Text fontSize="xs" mb="6">
          Toronto, Canada
        </Text>
        <Flex>
          <Text fontSize="xs">Starting at $50/day</Text>
          <Spacer />
          <Button size="xs">Expand</Button>
        </Flex>
      </Box>
    </Box>
  )
}

This destination card is contained in a 300px wide div with a 1px border. At the top, I added a 200px high grey box. This box is supposed to contain images of the city or a sample house but I decided to leave it out, and just use the colored box as a placeholder.

At the lower part, we added a badge with Chakra UI's Badge component. This Badge component comes in many colors. To change the color of ChakraUI's badge component, you just have to set a colorScheme prop to green, blue, or any other color you wish. Below the badge, we have the name of the city and the country. At the lowest part, we shows the starting price of renting a home in that city and a button to expand it (the button doesn't do anything though). I built this lower section containing the price and button with my favorite pair of components the Flex and Spacer component.

Why the Chakra UI Flex and Spacer components are super helpful

The Flex component is a major part of most of my designs. I mostly use it when I need a layout where I need one element to be fully aligned to the left and another to be located on the right. An example of this is a navigation bar example from Chakra UI's flex documentation.

const NavBar = () => (
  <Flex>
    <Box p="2">
      <Heading size="md">Chakra App</Heading>
    </Box>
    <Spacer />
    <Box>
      <Button colorScheme="teal" mr="4">
        Sign Up
      </Button>
      <Button colorScheme="teal">Log in</Button>
    </Box>
  </Flex>
)

This is not part of our design but you can try it out by adding the NavBar component to the top of App. Don't forget to remove it once you are done previewing it.

We needed the name to be on the left side of the navigation bar and the sign-up and login buttons to be on the right side. We created two Box components that will contain the left and the right container. We added the first box into the Flex component and we added a Spacer and then another Box containing the elements that are to be displayed on the right side.

In the destination card, we needed to add a left aligned text that shows the starting prices at the different cities and a right aligned button that we can use to view more about a destination on the right. This was achieved with Flex and Spacer.

<Flex>
  <Text fontSize="xs">Starting at $50/day</Text>
  <Spacer />
  <Button size="xs">Expand</Button>
</Flex>

We have the price text, a Spacer and then the button. This configuration appears a lot while building apps with Chakra UI so I believe it will be super helpful to always have this in mind.

Adding the Destination components to TopDestinations

Modify TopDestinations to look as below.

function TopDestinations() {
  return (
    <>
      <Text fontSize="5xl" fontWeight="bold" textAlign="center" mt="100px" mb="30px">
        Top Destinations
      </Text>
      <Flex w="min-content" m="0 auto">
        <Destination />
        <Destination />
        <Destination />
      </Flex>
    </>
  )
}

We needed to have two components that are not wrapped in each other but are independent so we added a JSX fragment. We added a Flex container that only occupies the width that it needs. We then used m="0 auto" to align the item horizontally.

Adding a features section

It is a very common practice on landing pages to see a section where we have an image on one half of the page and then an accompanying text on the other half of the page. We will implement that in our landing page too. We will do this with the SimpleGrid component which can be used to create horizontal sections that have equal widths or more easily said - grids.

A chit chat about the SimpleGrid component

The SimpleGrid component is a Chakra UI component that creates a grid. It accepts the columns prop that we use to choose how many columns our grid will have, which is 2 in our scenario. Another important property it accepts that we won't be using here is the gap property which defines how much space we will have between consecutive children.

We will be creating two components which are essentially the same. We are creating RightFeature and LeftFeature. In LeftFeature the text will be shown on the left and the image on the right. In RightFeature, however, we have the text on the right and the image on the left. The only difference between the two is the order of the children of the SimpleGrid component.

Import SimpleGrid from chakra-ui and add the following function to App.js

function RightFeature() {
  return (
    <Box mt={20}>
      <SimpleGrid columns={2}>
        <Box>
          <Box w="100%" m="0 auto" maxW="400px" h="300px" bg="gray.50"></Box>
        </Box>
        <Box>
          <Text fontSize="5xl" fontWeight="bold" maxW="600px">
            We house you very quickly
          </Text>
          <Text mt={4} maxW="600px">
            Using state of the art technology, we are able to match groups to the perfect housing
            that they need based on the size of the home needed, the features they require from the
            home and their budget.
          </Text>
          <Text color="blue.600" mt={4} fontSize="sm">
            How we match users
          </Text>
        </Box>
      </SimpleGrid>
    </Box>
  )
}

We have a Box that contains the two column grid. The grid then contains two Box elements as children. The first Box is supposed to contain the image, but to reduce complexity, we only added a placeholder box there. The second contains three sets of text. The first is a large title that tries to describe the feature and it is displayed in a larger font - 5xl. The next is an in-depth detail of the feature that we mentioned and it is displayed in a not so large font. And the large is supposed to be a link that will lead to another page that explains something, but we left it as a regular text component.

To render the component in our page, we edit our App function to include our newly created RightFeature component. Your App function should now look like this.

function App() {
  return (
    <ChakraProvider theme={theme}>
      <TopHeading />
      <TopDestinations />
      <RightFeature />
    </ChakraProvider>
  )
}

When you save and the development server reloads, you should see the feature section displayed.

To create the LeftFeature, we will have to switch the positions of the two items in the SimpleGrid However, we face a little problem. When we switch the positions, the text will be positioned on the extreme left. To fix this, we will have to make some changes to change how the RightFeature works. I will update the post whenever I find an easy workaround for this.

Adding a testimonial section

We also want to add a section where want to add some sample thoughts that people had about your product. This section will contain a large quote, the name of the person who said it and an extra line about where he works or a project he maintains.

Create the following function

function Testimonial() {
  return (
    <Box mt={32} w="100%" bg="gray.200" py={20}>
      <Text maxW="800px" fontSize="3xl" textAlign="center" m="0 auto">
        After using this product, I realized a great increase in the number of users that used our
        product. It has improved our load speed by 250%
      </Text>
      <Text fontSize="xl" color="blue.500" mt={4} textAlign="center">
        John Doe
      </Text>
      <Text fontSize="sm" textAlign="center">
        CEO at Belky
      </Text>
    </Box>
  )
}

We added a top margin to the container. In the container, we have a large text of size 3xl containing the quote. Below it we have blue text containing the name of the person and then the company. You can add Testimonial below <RightFeature /> in the App function.

Adding a footer

The last thing we want to add to our page is a footer. This footer will contain a little text that will describe what we do and also a few links to some important pages on our website.

Define a Footer function as follows

function Footer() {
  return (
    <Box mt={20} mb={12}>
      <Text fontSize="4xl" mt={12} fontWeight="bold" textAlign="center">
        Homelify
      </Text>
      <Text
        fontSize="2xl"
        textAlign="center"
        maxW="800px"
        m="0 auto"
        borderBottom="1px #bbb solid"
        mt={4}
        pb={10}
      >
        We match home owners with tourists and help the tourists get the home they want
      </Text>
      <SimpleGrid columns={3} w="max-content" gap={20} m="0 auto" mt={6}>
        <Text>Privacy</Text>
        <Text>Pricing</Text>
        <Text>Login</Text>
      </SimpleGrid>
    </Box>
  )
}

This footer gives us the title we are looking for and the subtitle too. We added a lower border below the subtitle. Below the border, we have the three texts that we will later turn into links.

What next?

One of the major reasons why I love Chakra UI is because it makes it very easy to set different styles for various breakpoints. Normally, if we want a green box, we will have <Box bg="green">, however, if we want the box to be red on small devices, blue on medium sized devices and green on large devices, we will have <Box bg={["red", "blue", "green"]}>. If we want to use the same style for the smallest and second smallest breakpoints, we just replace the second element in the array with null. When an element of the breakpoint is set to null, it takes previous style in that breakpoint.

To continue to learn more about Chakra UI, there is also a page on the Chakra UI documentation website that links to many helpful Chakra UI related resources.