Build an Angular Expandable and Collapsible Sidebar with Icons
Creating an expandable and collapsible sidebar in Angular can significantly enhance the user experience of your application. This tutorial provides a step-by-step guide to building such a sidebar, complete with icons and smooth transitions. We’ll cover everything from setting up the component structure to applying styles and logic for toggling the sidebar.
Why Use a Collapsible Sidebar?
A collapsible sidebar improves the usability of an application by:
- Saving screen space.
- Providing easy navigation.
- Keeping the interface clean and organized.
Step-by-Step Guide to Build the Sidebar
1. Set Up Your Angular Project
First, ensure you have Angular CLI installed. If not, run:
npm install -g @angular/cli
Create a new Angular project:
ng new angular-sidebar
cd angular-sidebar
Generate the necessary components:
ng generate component sidebar
2. Define the Sidebar Structure
app.component.html
This will serve as the main container for the application. Add the sidebar and a button for toggling its state:
<div class="app-container">
<div class="position-relative">
<app-sidebar
[isSidebarCollapsed]="isSidebarCollapsed"
(sidebarToggle)="onSidebarToggle()"
>
</app-sidebar>
<button
class="sidebar-toggle-btn"
[ngClass]="{ 'sidebar-collapsed': isSidebarCollapsed }"
(click)="onSidebarToggle()"
>
<i
[class]="
isSidebarCollapsed ? 'fas fa-arrow-right' : 'fas fa-arrow-left'
"
></i>
</button>
</div>
<main class="content" [ngClass]="{ 'content-expanded': isSidebarCollapsed }">
<div class="content-inner">Content goes here</div>
</main>
</div>
app.component.ts
Add the logic to manage the sidebar's state:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
isSidebarCollapsed = false;
onSidebarToggle() {
this.isSidebarCollapsed = !this.isSidebarCollapsed;
}
}
3. Implement the Sidebar Component
sidebar.component.html
Define the sidebar's HTML structure, including a menu with nested items:
<div class="sidebar" [ngClass]="{ 'sidebar-collapsed': isSidebarCollapsed }">
<div class="sidebar-header">
<a href="#" class="sidebar-logo">{{
isSidebarCollapsed ? 'C' : 'CodeWithChintan'
}}</a>
</div>
<div class="sidebar-menu">
<ul>
<ng-container *ngFor="let item of menuItems">
<li class="sidebar-menu-item">
<a
href="#"
class="sidebar-item"
[ngClass]="{
'has-children': item.children,
'menu-item-active': item.isOpen
}"
(click)="toggleMenuItem(item)"
>
<i [class]="item.icon"></i>
<span class="sidebar-item-text">{{ item.label }}</span>
<i
*ngIf="item.children && !isSidebarCollapsed"
class="fas fa-chevron-down sidebar-item-arrow"
[ngClass]="{ rotated: item.isOpen }"
></i>
</a>
<ul
*ngIf="item.children && !isSidebarCollapsed && item.isOpen"
class="sidebar-submenu"
>
<li *ngFor="let child of item.children">
<a href="#" class="sidebar-item sidebar-subitem">
<i [class]="child.icon"></i>
<span class="sidebar-item-text">{{ child.label }}</span>
</a>
</li>
</ul>
</li>
</ng-container>
</ul>
</div>
</div>
sidebar.component.ts
Handle the toggle logic for menu items and sidebar:
import { Component, EventEmitter, Input, Output } from '@angular/core';
interface MenuItem {
icon: string;
label: string;
children?: MenuItem[];
isOpen?: boolean;
}
@Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrls: ['./sidebar.component.scss'],
})
export class SidebarComponent {
@Input() isSidebarCollapsed = false;
@Output() sidebarToggle = new EventEmitter<void>();
menuItems: MenuItem[] = [
{
icon: 'fas fa-home',
label: 'Dashboard',
isOpen: false,
children: [
{ icon: 'fas fa-chart-pie', label: 'Analytics' },
{ icon: 'fas fa-tasks', label: 'Projects' },
]
},
{
icon: 'fas fa-cog',
label: 'Settings',
isOpen: false,
children: [
{ icon: 'fas fa-user', label: 'Profile' },
{ icon: 'fas fa-lock', label: 'Security' },
]
},
{
icon: 'fas fa-envelope',
label: 'Messages'
}
];
toggleSidebar() {
this.sidebarToggle.emit();
}
toggleMenuItem(item: MenuItem) {
// Only toggle if sidebar is not collapsed and item has children
if (!this.isSidebarCollapsed && item.children) {
item.isOpen = !item.isOpen;
}
}
}
4. Style the Sidebar
app.component.scss
Add global styles for layout and transitions:
.app-container {
display: flex;
height: 100vh;
overflow: hidden;
}
.content {
flex-grow: 1;
margin-left: 250px;
transition: all 0.3s ease-in-out;
background-color: #f4f6f7;
overflow-y: auto;
&-inner {
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
&-expanded {
margin-left: 50px;
}
}
.sidebar-toggle-btn {
position: absolute;
top: 1rem;
left: 200px; // Default position when sidebar is expanded
background-color: #2c3e50;
border: none;
color: #fff;
padding: 0.5rem;
border-top-right-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
cursor: pointer;
z-index: 1001;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
&:hover {
background-color: #34495e;
}
&.sidebar-collapsed {
left: 15px; // Position when sidebar is collapsed
}
}
sidebar.component.scss
Define styles for the sidebar and menu:
.sidebar {
background-color: #2c3e50;
color: #ecf0f1;
height: 100vh;
width: 250px;
position: fixed;
top: 0;
left: 0;
z-index: 1000;
transition: all 0.3s ease-in-out;
overflow-x: hidden;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
}
.sidebar-header {
display: flex;
justify-content: center;
align-items: center;
padding: 1.5rem;
position: relative;
}
.sidebar-logo {
color: #fff;
text-decoration: none;
font-size: 1.5rem;
font-weight: bold;
text-align: center;
}
.sidebar-menu {
padding: 1rem 0;
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
}
.sidebar-menu-item {
position: relative;
}
.sidebar-item {
display: flex;
align-items: center;
color: #ecf0f1;
text-decoration: none;
padding: 0.75rem 1rem;
transition: all 0.2s ease;
cursor: pointer;
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
&.menu-item-active {
background-color: rgba(255, 255, 255, 0.2);
}
i {
margin-right: 0.75rem;
&.sidebar-item-arrow {
margin-left: auto;
font-size: 0.8rem;
transition: transform 0.3s ease;
&.rotated {
transform: rotate(180deg);
}
}
}
&-text {
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
&.has-children {
position: relative;
}
}
.sidebar-submenu {
background-color: rgba(0, 0, 0, 0.1);
.sidebar-item {
padding-left: 3rem;
font-size: 0.9rem;
}
}
.sidebar-collapsed {
width: 50px;
.sidebar-menu-item {
position: static;
}
.sidebar-item {
i {
margin-right: 0;
}
&-text,
&-arrow {
opacity: 0;
width: 0;
overflow: hidden;
}
}
.sidebar-submenu {
display: none;
}
}
5. Run the Application
Start the development server:
ng serve
Navigate to http://localhost:4200/
to see your sidebar in action.
FAQs
How Do I Customize Sidebar Icons?
Modify the menuItems
array in sidebar.component.ts
and provide appropriate icon classes.
Can I Add Animations for Menu Expansion?
Yes, use Angular’s animation module to add smooth transitions when menus open and close.
How Do I Adjust Sidebar Width?
Update the width
property in sidebar.component.scss
for the expanded and collapsed states.
This guide covers all the essential steps to create a functional expandable and collapsible sidebar in Angular. You can further customize the design and functionality to meet your application needs.
Top comments (0)