How to Add Ant Design UI Framework to React

Throughout Part I of the course, we haven't made any changes to the presentation (i.e. CSS) of our client code. In this lesson, we'll introduce and use the Ant Design React UI framework to improve the appearance of our client application.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL with a single-time purchase.

Thumbnail for the \newline course TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL
  • [00:00 - 00:21] in this lesson, we'll introduce ant design into our app and use some of their components to make our list look better. The objective of this lesson isn't to convey what these certain components are by ant design, but more to convey how we can use a React UI framework to help improve the presentation of what we've already built.

    [00:22 - 00:41] So first and foremost, we'll head to the terminal and we'll install the ant design library as a main dependency. The ant design library is built with TypeScript so we won't have to install any additional type declaration files.

    [00:42 - 00:54] When installed, we can begin using components that ant design provides. To understand and see examples of components we'll use, the ant design documentation is really helpful.

    [00:55 - 01:04] The first components we'll use is the list component that ant design gives us. In the documentation site, we can see examples of how this list component can be used.

    [01:05 - 01:15] We'll look to mimic this basic list example shown here. The list component accepts a series of props with which we're only interested in a few.

    [01:16 - 01:25] Item layout dictates the layout of how we want each list item. Data source takes an array or collection of data that'll help prepare the list.

    [01:26 - 01:41] The list component uses the render prop pattern with the render item prop that dictates how each list item in the list will appear. First and foremost, we'll use this list component to render a list of titles just like we've done before.

    [01:42 - 02:01] So we'll import the list component in our listings TSX file from ant design. We'll create a constant variable with the same name as our preexisting list element variable, listings list.

    [02:02 - 02:10] We'll want our list displayed horizontally. And for the data source, we'll simply apply the listings data array that comes from our GraphQL query.

    [02:11 - 02:23] And in our render item prop, we'll simply have our components render just the title. We'll use the child list item and list item meta components that the list component provides.

    [02:24 - 02:43] (silence) We can now remove the old listings list variable we had before. We can notice that the listing argument from the render item function is type inferred based on the data source provided, which is great.

    [02:44 - 02:57] And we can see that our handle delete listing method isn't currently being used, but we'll use it shortly. If we take a look at our browser and inspect our UI, we can see all the markup ant design gives us.

    [02:58 - 03:05] However, we can't really witness any CSS whatsoever. This is because we haven't introduced the styles from the ant design style sheet.

    [03:06 - 03:23] To do so, we'll first create an index.css file at the root of the source folder within a styles folder. In our index.css file, we'll add the following imports to import the ant design style sheet into our index.css file.

    [03:24 - 03:46] In our source index.tsx file, we can tell our index file here to use the index.css file by simply importing it. The ability to import our style sheets in our components can be done thanks to Webpack and the configuration made in CreateReacta.

    [03:47 - 03:59] It's an incredibly useful feature that allows us to create blocks of style sheets for respective components. Since this index file is the root level component, applying styles here is applied to all children components as well.

    [04:00 - 04:14] Now upon revisiting our browser, we'll see some styles applied to our app. Let's add some custom padding to our list of listings before we update the actual list components.

    [04:15 - 04:34] We'll create a listings.css file in a styles folder within the listings module. We'll introduce a new class label listings and give it a margin of 20 pixels as well as a max width of 750 pixels.

    [04:35 - 04:55] In our listings component, we'll import the newly created listings style sheet and specify the listings class in the root div element. If we take a look at our browser, we can now see the margin and max width applied.

    [04:56 - 05:00] Awesome. Let's now look to populate our list a little more.

    [05:01 - 05:11] The list item meta component can take in an avatar and description props as well. For description, we'll specify a value of the listing address.

    [05:12 - 05:28] For avatar, we'll use an avatar component that AntDesign provides. We'll import this avatar component from AntDesign and provide a source of listing image.

    [05:29 - 05:40] The avatar component also takes a shape and size prop as well to help control the dimensions of the avatar. We'll give it a shape of square in a size of 48.

    [05:41 - 05:54] We'll now be presented with a listing avatar and address description along with the listing title. We can still see however that we're missing the ability to delete a listing.

    [05:55 - 06:12] The list item components can take in actions prop, which can be an array of JSX elements that represent the actions that can be taken for a certain list item. We'll introduce this actions prop and attempt to place a single element value.

    [06:13 - 06:44] Our element will be the main button component that AntDesign provides. We'll import button, place it as the first item in our array as well as provide an on-click prop that will have the button trigger the handle delete listing method when clicked.

    [06:45 - 06:56] AntDesign's button also takes a type prop to control how the button is to appear. To get the primary blue color, we'll apply a type equal primary prop.

    [06:57 - 07:06] And there we have it. Each list item now has a button and deleting a listing now works.

    [07:07 - 07:24] We won't make any more changes to the list component, but now look to optimize the other parts of our list. One thing to note, instead of importing the different and design components from different files, we're able to import all the components directly from the main and design file.

    [07:25 - 07:40] When we delete a listing, we're still presented with a deletion and progress header element at the bottom of our list. We can probably look to use a better loading indicator of sorts.

    [07:41 - 07:54] AntDesign offers a component labeled spin that helps display the loading state of a page or a section. Its usage is pretty simple and can be placed within a container while conditionally controlling its spinning prop.

    [07:55 - 08:11] Let's import the spin component and wrap the inner contents of our return markup. To control when the spin component is visible, we'll set its spinning prop to the value of delete listing loading, the value where our mutation loading is true.

    [08:12 - 08:31] We could also remove the delete listing loading message elements we've created before to convey that a deletion is in progress. Now, when a deletion is in made and is in flight, we're presented with a loading spinner and we're unable to interact with our list while a deletion is still being made.

    [08:32 - 08:51] When our parent listings query is being made, we have a simple loading message we've shown. Let's look to display a nice-looking skeleton UI instead.

    [08:52 - 09:04] AntDesign has a skeleton component that can be used in multiple different ways. We'll stick with a simple approach, by looking to render a component we'll create that uses the skeleton element.

    [09:05 - 09:25] To prevent introducing any more markup in this component file, we'll create the component that would render the skeleton in another component file we'll call Listing's Skeleton. We'll keep this new component in a components folder within the listings module to represent that it's a child component of this module.

    [09:26 - 09:43] We'll create the components folder and a listings skeleton folder within that will contain a listings skeleton.tsx file. In the listings skeleton component file, we'll import React as well as the skeleton component from AntDesign.

    [09:44 - 10:01] To get us started, let's simply have the listings skeleton component render the AddDesign skeleton component directly. We'll create an index file in the listings skeleton folder and re-export the listings skeleton component.

    [10:02 - 10:23] We'll also do the same for the components index file. In the listings components, we'll import the newly created listings skeleton components from the child components folder, and we'll create a new component.

    [10:24 - 10:42] When our query is in the loading state, we'll render the listings skeleton component directly. When we head to the browser and make a refresh, we'll see the skeleton UI briefly, which tells us we're appropriately rendering the listings skeleton components.

    [10:43 - 10:59] Let's now customize the listing skeleton component to better resemble the list we're about to render. To make things easier as we build it out, we'll temporarily force the rendering of the listings skeleton component to view the changes we make.

    [11:00 - 11:12] First, we'll look to add an equivalent margin and width constraint to the components. To do so, we'll simply wrap listings skeleton with a div element that has a class name of listings.

    [11:13 - 11:25] We'll see that the skeleton UI is positioned more accordingly. Let's now look to add the static title that we also see in the listings components.

    [11:26 - 11:39] We'll pass in the title available in listing as a prop to listing skeleton. So in listing skeleton, we'll create a props interface for the component since we'll expect a title prop of string type.

    [11:40 - 11:54] We'll use this prop in an H2 tag and wrap our return statement with a parent div element. Where listing skeleton is being rendered, we'll pass the title prop along.

    [11:55 - 12:06] Now we're presented with a title at the top of our skeleton. Let's look to make our skeleton resemble more of a list.

    [12:07 - 12:22] The skeleton component has a paragraph prop that takes an object and can help control the amount of rows being displayed. Let's edit the skeleton component in listing skeleton and specify a single row for the paragraph.

    [12:23 - 12:36] We'll also add the active prop to give our skeleton the active blinking state. We're now presented with a single row after the header row.

    [12:37 - 12:51] To mimic a list, we'll introduce two more identical skeleton components. And design provides a divider component that helps in displaying a divide between sections and text.

    [12:52 - 13:05] We'll import the divider component and place them between each skeleton component. We'll now see a neat separation between each skeleton portion.

    [13:06 - 13:19] We can see that each skeleton paragraph adds a margin perhaps slightly larger than what we need to mimic our existing list. We can actually modify the styles and design provides directly if we want to.

    [13:20 - 13:30] Let's see an example of this. We'll first introduce a listings skeleton CSS file in a styles folder within the listings skeleton module.

    [13:31 - 13:56] We'll import the listings skeleton style sheet in our listing skeleton components and we'll apply a listings skeleton class in the parent div element of listing skeleton. In our browser, when we inspect the UI, we can see a margin of 24 pixels applied to the divider.

    [13:57 - 14:15] In our custom style sheet, we can reference this divider horizontal class and provide a margin of 12 pixels zero. When we survey the paragraph row, we can see a margin top of 24 pixels.

    [14:16 - 14:29] We can look to reduce this by modifying the style of the relevant class in our style sheet to 12 pixels. And that's all we'll do.

    [14:30 - 14:51] Now, it's important to remember that modifying styles through custom means affects the intended styles brought forth by the design framework and doesn't really have to be done. In addition, there's also more robust ways to modify styles in a global matter that, and design, does provide some documentation for that we'll provide links.

    [14:52 - 15:10] This is just an illustration of how it's possible to modify the framework styles in certain areas if we want to. In our listings component, we'll reapply the loading property as the boolean to control whether our listing skeleton component is to be rendered.

    [15:11 - 15:25] Now, we're presented with a neat simple skeleton when our query is being made. When our listings query ever fails, let's look to present the message we had before within an alert banner of sorts .

    [15:26 - 15:39] And design provides an alert banner component to do just this. We'll look to have this alert banner be shown at the top of the skeleton loading UI if our query ever fails.

    [15:40 - 15:59] In that instance, we'll slightly modify our listings skeleton components to accept an error prop of type boolean, with which we'll give a default parameter value of false. We'll import the alert component and conditionally show it when error is true.

    [16:00 - 16:12] Our alert component will have the type prop given a value of error as well, including the appropriate message we want to say. Uh-oh, something went wrong, please try again later.

    [16:13 - 16:40] In listings, let's look to render the listings skeleton component again, with the error prop set to true when our query ever fails. If we temporarily force this element to render, we can see an alert message be shown at the top of our skeleton list.

    [16:41 - 16:53] Let's add a little margin between the alert and the title. In listings, skeleton will add a listings skeleton alert class to the alert components.

    [16:54 - 17:15] In the CSS file, we'll apply some amount of margin, perhaps margin bottom 20 pixels, to the alert class we've just created. Our alert now has a little margin applied below it.

    [17:16 - 17:20] Awesome. We'll remove the forced render we're doing of the error state now.

    [17:21 - 17:53] When an error occurs from deleting a listing, we'll also want to display an alert banner of sorts, just like we've done when a query fails, so in the listings component file, we'll also import the alert component. We'll create a constant variable called delete listing error alerts, that would conditionally show the alert component if the delete listing error boolean is true, and we'll add a listings alert class to it.

    [17:54 - 18:04] We'll specify the type prop to be error, and it'll have the same message as our other alert components. Uh-oh, something went wrong, please try again later.

    [18:05 - 18:21] In the listings CSS file, we'll add a little margin bottom to the listings alert class. Now when we delete a listing and if it fails, we'll receive an error alert at the top of our list.

    [18:22 - 18:31] If we force this element to appear, it will look just like the alert we had before. Notice how content behaves when a query or a mutation fails.

    [18:32 - 18:45] When the query fails, we have no data to display, so we simply display the alert above the skeleton UI. When the mutation fails, we already had some information in the UI, so we were sort of displaying the alert above the existing lists.

    [18:46 - 18:57] And this brings us to the end of this lesson. By using ant design, we were able to leverage many different components from the framework to style and make our application more presentable.

    [18:58 - 19:09] Two important notes we like to make before we close. The first note is, our application's core behavior is practically the same as what we had in the previous lesson.

    [19:10 - 19:30] We make our query and mutation, we display a loading indicator of sorts when the query or mutation is in flight, we display an error alert when either the query or mutation fails. We've just been able to leverage ant design and utilize the styles and components and design provides for each of these different scenarios.

    [19:31 - 19:43] There's a numerous different components behaviors we can do, and there's no right answer. It's up to the developer or the development team to discuss and address what the intended UI behavior should be.

    [19:44 - 19:57] The other important point to make is that this lesson isn't a focus on the components we've just used from ant design. Like we mentioned, there's many other things we could have done that we haven't done.

    [19:58 - 20:17] The main takeaway here is how intuitive it is to use a design framework to leverage the components available to get the desired outcome. We highly encourage you to spend some time, go through the documentation and ant design provides, introduce different components, to get a good feel of what we aim to do here.

    [20:18 - 20:25] With that said, this concludes the development needed in part 1 of this course. Bravo!

    [20:26 - 20:35] [ Silence ]