Creating a Responsive Sidebar in Ant Design
How I worked around to create a responsive sidebar I liked
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.
When I move to a device with a smaller screen, the sidebar should disappear, and there should be an icon on the navigation bar.
When I click on that icon, it displays the contents of the sidebar.
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.
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. TheDrawer
takes in aMenu
component and renders it when theDrawer
is 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!