Styling with Ant Design
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.
📝 This lesson's quiz can be found - here. 🗒️ Solutions for this lesson's quiz can be found - here.
In this lesson, we'll introduce the Ant Design React UI framework and use some of the components from the Ant Design framework to make our client application look more presentable. The objective of this lesson isn't to convey what certain components given to us by Ant Design are but more to convey how we can use a React UI framework to help improve the presentation of what we've built.
First and foremost, we'll install the antd
library into our client application.
client $: npm install antd
The antd
library is built with TypeScript so we won't have to install any additional type declaration files. When installed, we can begin to use the components that Ant Design provides.
The Ant Design documentation provides a detailed overview of all the different components Ant Design provides as well as the
props
they accept and examples of their use. In this lesson, we'll simply highlight and use a few certain components.
Ant Design has released a new major version - v4! v4 brings in a lot of out of the box beneficial changes such as upgrading design specifications, introducing a dark theme, making the entire bundle size smaller, etc.
In our course, we've used version v3 throughout. With an upgrade to v4, the vast majority of things we've done in the course remains the same except for a few minor changes that'll need to be made. If you're interested in following along exactly what we've done in our video lessons, do install the latest 3.x.x version of Ant Design (e.g.
npm install [email protected]^3.0.0
). If you're interested in seeing how v3 can be upgraded to v4, do feel free to refer to Ant Design's V3 to V4 migration guide for more details.
<List>
#
The first component we'll use is Ant Design's <List>
component. We'll use the <List>
component to first render a list of titles
from the listings
data we retrieve from our GraphQL API.
We'll import the List
component module in our Listings.tsx
file.
import { List } from "antd";
We'll modify the listingsList
constant variable we had before to now use Ant Design's <List>
component to render a list of elements. As we render the <List>
component, we'll use the component's itemLayout
, dataSource
, and renderItem
props.
Our listingsList
constant in our <Listings>
component will look like the following:
const listingsList = listings ? (
<List
itemLayout="horizontal"
dataSource={listings}
renderItem={listing => (
<List.Item>
<List.Item.Meta title={listing.title} />
</List.Item>
)}
/>
) : null;
The
itemLayout
prop dictates the layout of how we want each list item to be rendered with which we've given a value of"horizontal"
.dataSource
takes an array or collection of data that'll help prepare the list.The
renderItem
prop is an example of the render props pattern that dictates how each list item is to be rendered. We're using the child<List.Item>
and<List.Item.Meta>
components to render the title of each iterated listing.
The <Listings>
component handleDeleteListing()
method isn't currently being used but we'll use it again shortly.
Though at this moment we'll be rendering the markup from Ant Design, we won't see any CSS that Ant Design gives us. If we take a look at the "use in create-react-app
" section of the Ant Design documentation we can that Ant Design expects us to import an accompanying CSS file from the installed antd
library.
We'll create an index.css
file in a styles/
folder at the root of the src/
folder.
client/
src/
styles/
index.css
// ...
// ...
In the index.css
file, we'll add the following @import
to import the Ant Design stylesheet into our index.css
file.
@import "~antd/dist/antd.css";
In our src/index.tsx
file, we can tell our index.tsx
file to use the index.css
file by simply importing it.
import "./styles/index.css";
The ability to simply import our stylesheet in our components can be done thanks to Webpack and the configuration made in create-react-app
. This is an incredibly useful feature that allows us to create blocks of stylesheets for respective components. Since index.tsx
is the root level "component", applying styles here is applied to all children components as well.
The Ant Design documentation does also show the capability of ejecting the
create-react-app
configuration and using the Ant Design'sbabel-plugin-import
library to allow for the importing of components with reduced CSS bundle sizes.In this course, we'll keep things simple and introduce components from Ant Design just like we've done for the
<List>
component.
Though we're not there yet, when taking a look at our browser - we'll see the markup and styling Ant Design's <List>
component gives us!

We'll look to add some custom padding to our list of Listings before we further update the <List>
component. We'll create a styles/Listings.css
file in the Listings/
folder to act as the stylesheet for the <Listings>
component.
client/
src/
sections/
Listings/
styles/
Listings.css
//...
In the Listings.css
file, we'll introduce a .listings
class and give it a margin of 20px
as well as a max-width of 750px
.
.listings {
margin: 20px;
max-width: 750px;
}
In our <Listings>
component, we'll import the newly created Listings.css
stylesheet and specify the .listings
class in the root <div>
element of the component.
// ...
import "./styles/Listings.css";
// ...
export const Listings = ({ title }: Props) => {
// ...
return (
<div className="listings">
<h2>{title}</h2>
{listingsList}
{deleteListingLoadingMessage}
{deleteListingErrorMessage}
</div>
);
};
If we take a look at our app, we can see the margin and max-width be applied to our list.

We'll now look to populate our list a little more. The <List.Item.Meta>
component can take an avatar
and description
prop. For the description
prop, we'll specify a value of the listing address. For the avatar
prop, we'll import and use the <Avatar>
component that Ant Design provides. We'll import and use the <Avatar>
component from antd
and provide a src
of listing.image
. The <Avatar>
component also takes a shape
and size
prop with which we'll provide a shape
of "square"
and a size
of 48
.
Our listingsList
constant variable will now look like the following:
// ...
import { Avatar, List } from "antd";
// ...
export const Listings = ({ title }: Props) => {
// ...
const listingsList = listings ? (
<List
itemLayout="horizontal"
dataSource={listings}
renderItem={listing => (
<List.Item>
<List.Item.Meta
title={listing.title}
description={listing.address}
avatar={<Avatar src={listing.image} shape="square" size={48} />}
/>
</List.Item>
)}
/>
) : null;
// ...
};
Just from those changes alone, we'll now have avatars and address descriptions for each of our listing items!

We're still missing the ability to delete a listing. The <List.Item>
component can take an 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. Our element will be the <Button>
component from Ant Design.
We'll import the <Button>
component and place it as the first item in our array in the actions
prop. The <Button>
component will have an onClick
prop that will have the button trigger the component handleDeleteListing()
method when clicked. Ant Design's <Button>
component also takes a type
prop to control how the button is to appear. To get the primary blue color, we'll apply the value of "primary"
to the type
prop.
// ...
import { Avatar, Button, List } from "antd";
// ...
export const Listings = ({ title }: Props) => {
// ...
const listingsList = listings ? (
<List
itemLayout="horizontal"
dataSource={listings}
renderItem={listing => (
<List.Item
actions={[
<Button type="primary" onClick={() => handleDeleteListing(listing.id)}>
Delete
</Button>
]}
>
<List.Item.Meta
title={listing.title}
description={listing.address}
avatar={<Avatar src={listing.image} shape="square" size={48} />}
/>
</List.Item>
)}
/>
) : null;
// ...
};
A Delete
button will now appear in each list item, and clicking it will allow us to delete the listing from the list!

We won't make any more changes to the <List>
component but look to optimize the other parts of our list.
<Spin>
#
When we delete a listing, we're still presented with a Deletion in progress...
header element at the bottom of our list. We can probably look to use a better loading indicator from Ant Design.
Ant Design offers a component labeled <Spin>
that helps display the loading state of a page or a section.
In the Listings.tsx
component file, we'll import the Spin
component module and wrap the inner contents of our component markup with the <Spin>
component. To control when the <Spin>
component is visible, we'll set its spinning
prop to the value of deleteListingLoading
which is the value that represents the loading state of our mutation request. We can also remove the deleteListingLoadingMessage
element we've created before.
// ...
import { Avatar, Button, List, Spin } from "antd";
// ...
export const Listings = ({ title }: Props) => {
// ...
return (
<div className="listings">
<Spin spinning={deleteListingLoading}>
<h2>{title}</h2>
{listingsList}
{deleteListingErrorMessage}
</Spin>
</div>
);
};
When deletion is in progress, we'll now be presented with a loading spinner.

<Skeleton>
#
When our parent listings
query is being made, we have a simple Loading...
message be shown. Let's look to display a skeleton UI instead. Ant Design has a <Skeleton>
component that can be used in multiple different ways. We'll stick with a simple approach by looking to render a custom component that uses the <Skeleton>
element when the query is loading.
We'll keep our new component in a components/
folder within the Listings/
module to represent that it's a child component of <Listings>
. We'll create the components/
folder and a ListingsSkeleton/
folder within that will contain a ListingsSkeleton.tsx
file and an index.ts
file.
This page is a preview of TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL