Creating a Responsive Sidebar in Ant Design

How I worked around to create a responsive sidebar I liked

Chow Jia Ying
5 min readJul 25, 2020
A Responsive SideBar in Ant Design
Image by Author

Background

I was working on a React app that made use of the Ant Design frontend library and wanted to challenge myself to make a responsive sidebar. I started looking at the responsive sidebar examples, but none of the examples fit what I wanted to do.

After some thought, I decided to work around this. This documents how I created the sidebar.

How the sidebar works

The sidebar should have the following features:

When viewing the app on larger screen sizes, the sidebar should be on the left of the page.

A sidebar on the left of the page
Screenshot by Author

When I move to a device with a smaller screen, the sidebar should disappear, and there should be an icon on the navigation bar.

Navbar icon appears in smaller screen sizes
Screenshot by Author

When I click on that icon, it displays the contents of the sidebar.

A Responsive SideBar in Ant Design
Screenshot by Author

Both menus should have the same topic item being selected. For example, when I select ‘Topic 2’ on the sidebar, the other menu should also have ‘Topic 2’ selected and vice versa.

Selected items for both menus are the same
Screenshot by Author

Implementation

My solution involves splitting this into two components: the SideBar and the NavBar.

SideBar

With Ant Design, a SideBar can be created with aLayout.Sider component that takes in a Menu component. With that, here’s the code for the SideBar component, in SideBar.js :

import React from "react";
import { Layout } from "antd";
import "./SideBar.css"const SideBar = ({ menu }) => {
return (
<Layout.Sider
className="sidebar"
breakpoint={"lg"}
theme="light"
collapsedWidth={0}
trigger={null}
>
{menu}
</Layout.Sider>
);
};
export default SideBar;

The Sidebar takes in a menu prop, which contains the menu to display the contents with. Since the NavBar also needs the same menu, the menu component is abstracted to another component instead of being hardcoded in the Sidebar.

collapsedWidth is set to 0 so the sidebar fully closes. Without this prop, the SideBar will only be minimised.

trigger is set to null to prevent an icon from being shown when the SideBar closes. It’s mostly a stylistic issue because I didn’t like how the icon was blocking the right side of the page.

Styling SideBar

The SideBar can be further styled in a separate CSS file. In SideBar.css , I created a sidebar class and styled it like this:

.sidebar {
height: 100vh;
margin-right: 24px;
}

Note that height is set to 100vh because I want it to span 100% of the viewport (size of the browser window).

NavBar

The NavBar contains three components:

  • A button to click on to reveal the menu when the screen size is small
  • A Drawer, which is a panel that displays content on the left edge of the screen. The Drawer takes in a Menu component and renders it when the Draweris made visible.
  • Optionally, the logo of the website.

The visibility of the Drawer is controlled by a React hook. Here’s the code below, in NavBar.js:

import React, { useState } from "react";
import { Drawer, Button } from "antd";
import { MenuOutlined } from "@ant-design/icons";
import "./NavBar.css";import logo from "./../../logo.svg";const NavBar = ({ menu }) => {
const [visible, setVisible] = useState(false);
return (
<nav className="navbar">
<Button
className="menu"
type="primary"
icon={<MenuOutlined />}
onClick={() => setVisible(true)}
/>
<Drawer
title="Topics"
placement="left"
onClick={() => setVisible(false)}
onClose={() => setVisible(false)}
visible={visible}
>
{menu}
</Drawer>
<a href="/"><img src={logo} className="logo" alt="logo" /></a>
</nav>
);
};
export default NavBar;

Most importantly, the button has a menu class, which is defined in NavBar.css :

.navbar {
background-color: white;
padding-left: 2rem;
padding-top: 1rem;
padding-bottom: 1rem;
}
@media (min-width: 992px) {
.menu {
display: none;
}
}
.logo {
height: 32px;
margin-left: 1rem;
}

I used a media query to display the button only in devices with smaller screen sizes. The button disappears when the website is viewed on devices with larger screen sizes.

TopicMenu

The TopicMenu component is a component that displays a menu. I passed in the selectedKey and changeSelectedKey props to make the first item active by default, and change the active item when an item is clicked on.

import React from "react";
import {Menu} from "antd";
const TopicMenu = ({ topics, selectedKey, changeSelectedKey }) => {
const styledTopics = [];
topics.forEach((topic, index) =>
styledTopics.push(
<Menu.Item key={index} onClick={changeSelectedKey}>
{topic}
</Menu.Item>
)
);

return (
<Menu mode="inline" selectedKeys={[selectedKey]}>
{styledTopics}
</Menu>
);
}
export default TopicMenu;

Higher-level logic

The App component is the parent component which renders the aforementioned NavBar and SideBar . It also passes data and functions to its children components.

import React, { useState } from "react";
import { Layout } from "antd";
import TopicMenu from "./components/TopicMenu";
import "./App.css";import NavBar from "./components/NavBar/NavBar";
import SideBar from "./components/SideBar/SideBar";
function App() {
const topics = ["First topic", "Second topic", "Third topic"];
const [contentIndex, setContentIndex] = useState(0);
const [selectedKey, setSelectedKey] = useState("0");
const changeSelectedKey = (event) => {
const key = event.key;
setSelectedKey(key);
setContentIndex(+key);
};
const Menu = (
<TopicMenu
topics={topics}
selectedKey={selectedKey}
changeSelectedKey={changeSelectedKey}
/>
);
return (
<div className="App">
<NavBar menu={Menu} />
<Layout>
<SideBar menu={Menu} />
<Layout.Content className="content">
{topics[contentIndex]}
</Layout.Content>
</Layout>
</div>
);
}
export default App;

As seen from the code, the App component uses a React hook to manage the selected topic in the SideBar/NavBar components. It passes the TopicMenu component to both components as well, so they render the same data.

Styling App

In `App.css`, add the following in:

@import "~antd/dist/antd.css";
@import url("https://fonts.googleapis.com/css?family=Open+Sans");
.App {
font-family: "Open Sans", Arial, Helvetica, sans-serif;
}
.content {
padding: 1rem;
}

The @import "~-ant/dist/antd.css” statement is important to import default CSS styling from Ant Design. Importing the Open Sans font is optional and you can import any font you like.

Conclusion

The full code is available here: https://github.com/C-likethis123/ant-responsive-sidebar

I deployed the app to Github pages here: https://c-likethis123.github.io/ant-responsive-sidebar/

I hope this helped developers who want to integrate a responsive sidebar in their app. With a little ingenuity, we can make use of library components to create specific features we want.

Edit: Added an explanation for the App.css and SideBar.css files. Thanks to Хүрэлхуяг М and Kimtyjslove for highlighting this!

--

--