{{ notification.title }}
{{ notification.message }}
{{ notification.timestamp | date:'short' }}
Angular component for creating a resizeable sidenav with dynamic and static content.
https://github.com/fsegurai/ngx-sidenav
angular component component-library menu navigation ngx-sidenav npm sidenav typescript typescript-library
Last synced: 3 months ago
JSON representation
Angular component for creating a resizeable sidenav with dynamic and static content.
`@fsegurai/ngx-sidenav` is a modern, flexible, and feature-rich sidenav component library for Angular applications. Built with Angular's latest features, including signals, standalone components, and the new control flow syntax.
## β¨ Features
- π― **Modern Angular**: Built with Angular 20+ features (signals, standalone components, control flow)
- π± **Responsive Design**: Adaptive layout with collapsible and resizable functionality
- π **Dynamic Content**: Support for both declarative HTML and programmatic content management
- π¨ **Customizable**: Extensive theming and styling options
- π **Performance**: Optimized with OnPush change detection and signals
- πΎ **Persistent State**: Auto-save/restore sidenav state and navigation stack
- π§© **Component Support**: Render custom Angular components within the sidenav
- πͺ **Animations**: Smooth transitions and visual feedback
## π Table of Contents
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Usage Patterns](#usage-patterns)
- [Declarative HTML Usage](#declarative-html-usage)
- [Programmatic Service Usage](#programmatic-service-usage)
- [Styling and Theming](#styling-and-theming)
- [API Reference](#api-reference)
- [Advanced Examples](#advanced-examples)
- [Demo Application](#demo-application)
- [Contributing](#contributing)
- [License](#license)
## π Installation
```bash
npm install @fsegurai/ngx-sidenav --save
```
## β‘ Quick Start
```typescript
import { Component, signal } from '@angular/core';
import { Sidenav, SidenavMenu, StackMenuItem } from '@fsegurai/ngx-sidenav';
@Component({
selector: 'app-root',
imports: [Sidenav, SidenavMenu],
template: `
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
protected readonly menuItems = signal([
{
label: 'Dashboard',
icon: 'dashboard',
route: '/dashboard',
iconType: 'material'
},
{
label: 'Settings',
icon: 'settings',
iconType: 'material',
children: [
{ label: 'Profile', route: '/settings/profile' },
{ label: 'Security', route: '/settings/security' }
]
}
]);
}
```
## π§ Usage Patterns
### Declarative HTML Usage
Perfect for static menu structures defined at compile time:
```typescript
import { Component, signal } from '@angular/core';
import { Sidenav, SidenavMenu, StackMenuItem } from '@fsegurai/ngx-sidenav';
@Component({
selector: 'app-declarative',
imports: [Sidenav, SidenavMenu],
template: `
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeclarativeComponent {
protected readonly menuItems = signal([
{ label: 'Navigation', isTitle: true },
{
label: 'Analytics',
icon: 'analytics',
iconType: 'material',
badge: '5',
badgeColor: 'primary',
children: [
{
label: 'Overview',
route: '/analytics/overview',
summary: 'View key metrics and insights'
},
{
label: 'Reports',
route: '/analytics/reports',
icon: 'assessment',
badge: 'NEW'
},
{
label: 'Performance',
icon: 'speed',
children: [
{ label: 'Load Times', route: '/analytics/performance/load' },
{ label: 'Memory Usage', route: '/analytics/performance/memory' }
]
}
]
},
{
label: 'User Management',
icon: 'people',
route: '/users',
tooltip: 'Manage application users'
},
{ label: 'Tools', isTitle: true },
{
label: 'Settings',
icon: 'settings',
disabled: false,
children: [
{ label: 'General', route: '/settings/general' },
{ label: 'Security', route: '/settings/security' },
{ label: 'Notifications', route: '/settings/notifications' }
]
}
]);
protected readonly userAvatar = signal('/assets/user-avatar.jpg');
protected readonly userName = signal('John Doe');
onSidenavOpened() {
console.log('Sidenav opened');
}
onSidenavClosed() {
console.log('Sidenav closed');
}
onSidenavResized(width: number) {
console.log('Sidenav resized to:', width);
}
}
```
### Programmatic Service Usage
Ideal for dynamic content management and complex navigation flows:
```typescript
import { Component, inject, signal } from '@angular/core';
import { Sidenav, SidenavService, MenuStackItem, ComponentStackItem } from '@fsegurai/ngx-sidenav';
@Component({
selector: 'app-programmatic',
imports: [Sidenav],
template: `
Dashboard Menu
User Profile
Settings
Custom Widget
β Back
`,
styles: [`
.app-container {
display: flex;
height: 100vh;
}
.main-content {
flex: 1;
padding: 2rem;
}
.controls {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
}
.controls button {
padding: 0.5rem 1rem;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
cursor: pointer;
}
.controls button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProgrammaticComponent {
private readonly sidenavService = inject(SidenavService);
// Computed signal to track navigation state
protected readonly canGoBack = this.sidenavService.canGoBack;
showDashboard() {
const dashboardMenu: MenuStackItem = {
type: 'menu',
title: 'Dashboard',
items: [
{
label: 'Overview',
icon: 'dashboard',
route: '/dashboard/overview',
iconType: 'material'
},
{
label: 'Analytics',
icon: 'analytics',
badge: '12',
badgeColor: 'accent',
children: [
{ label: 'Traffic', route: '/dashboard/traffic' },
{ label: 'Conversions', route: '/dashboard/conversions' },
{ label: 'Revenue', route: '/dashboard/revenue' }
]
},
{
label: 'Reports',
icon: 'assessment',
route: '/dashboard/reports'
}
]
};
this.sidenavService.push({ type: 'menu', items: dashboardMenu});
}
showUserProfile() {
const profileMenu: MenuStackItem = {
type: 'menu',
title: 'User Profile',
badge: '3',
badgeColor: 'primary',
items: [
{
label: 'Personal Info',
icon: 'person',
route: '/profile/personal',
summary: 'Manage your personal information'
},
{
label: 'Account Settings',
icon: 'settings',
children: [
{ label: 'Password', route: '/profile/password' },
{ label: 'Two-Factor Auth', route: '/profile/2fa' },
{ label: 'API Keys', route: '/profile/api-keys' }
]
},
{
label: 'Preferences',
icon: 'tune',
route: '/profile/preferences'
},
{ label: 'Danger Zone', isTitle: true },
{
label: 'Delete Account',
icon: 'delete_forever',
route: '/profile/delete',
disabled: false
}
]
};
this.sidenavService.push({ type: 'menu', items: profileMenu});
}
showSettings() {
const settingsMenu: MenuStackItem = {
type: 'menu',
title: 'Application Settings',
items: [
{ label: 'General', isTitle: true },
{
label: 'Theme',
icon: 'palette',
children: [
{ label: 'Light Mode', route: '/settings/theme/light' },
{ label: 'Dark Mode', route: '/settings/theme/dark' },
{ label: 'Auto', route: '/settings/theme/auto' }
]
},
{
label: 'Language',
icon: 'language',
route: '/settings/language'
},
{ label: 'Advanced', isTitle: true },
{
label: 'Developer Tools',
icon: 'code',
children: [
{ label: 'API Console', route: '/settings/api-console' },
{ label: 'Debug Mode', route: '/settings/debug' },
{ label: 'Feature Flags', route: '/settings/features' }
]
}
]
};
this.sidenavService.push({ type: 'menu', items: settingsMenu});
}
showCustomWidget() {
// Example of pushing a custom component
const widgetComponent: ComponentStackItem = {
type: 'component',
component: CustomWidgetComponent,
componentData: {
title: 'System Status',
data: {
uptime: '99.9%',
activeUsers: 1234,
systemHealth: 'excellent'
}
}
};
this.sidenavService.push({ type: 'component', component: widgetComponent});
}
async goBack() {
await this.sidenavService.pop();
}
// Initialize with default menu
ngOnInit() {
this.showDashboard();
}
}
// Example custom component for the sidenav
@Component({
selector: 'custom-widget',
template: `
`,
styles: [`
.widget-container {
padding: 1.5rem;
}
.metrics {
margin: 1rem 0;
}
.metric {
display: flex;
justify-content: space-between;
padding: 0.5rem 0;
border-bottom: 1px solid #eee;
}
.value.excellent { color: #4caf50; }
.value.good { color: #ff9800; }
.value.poor { color: #f44336; }
.actions {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
.actions button {
padding: 0.5rem 1rem;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
cursor: pointer;
}
`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomWidgetComponent {
readonly title = input.required();
readonly data = input.required();
protected readonly metrics = computed(() => [
{ label: 'Uptime', value: this.data().uptime, status: 'excellent' },
{ label: 'Active Users', value: this.data().activeUsers.toLocaleString(), status: 'good' },
{ label: 'System Health', value: this.data().systemHealth, status: 'excellent' }
]);
refresh() {
console.log('Refreshing widget data...');
}
exportData() {
console.log('Exporting data...');
}
}
```
### Styling and Theming
Customize the appearance using CSS variables:
## SIDENAV
- `--ngx-sidenav-container-background-color`: Defines the background color of the sidenav container.
- `--ngx-sidenav-link-item-parent-background-color`: Defines the background color of the parent link item in the sidenav.
- `--ngx-sidenav-link-item-parent-text-color`: Defines the text color of the parent link item in the sidenav.
- `--ngx-sidenav-link-item-text-color`: Defines the text color of the link item in the sidenav.
- `--ngx-sidenav-link-item-border-left-color`: Defines the left border color of the link item in the sidenav.
- `--ngx-sidenav-link-item-text-color-hover`: Defines the text color of the link item when hovered.
- `--ngx-sidenav-link-item-text-color-active`: Defines the text color of the link item when active.
- `--ngx-sidenav-link-item-border-left-color-hover`: Defines the left border color of the link item when hovered.
- `--ngx-sidenav-link-item-border-left-color-active`: Defines the left border color of the link item when active.
- `--ngx-sidenav-link-item-background-color-hover`: Defines the background color of the link item when hovered.
- `--ngx-sidenav-link-item-background-color-active`: Defines the background color of the link item when active.
- `--ngx-sidenav-link-item-box-shadow-color-hover`: Defines the box-shadow color of the link item when hovered.
- `--ngx-sidenav-link-item-box-shadow-color-active`: Defines the box-shadow color of the link item when active.
- `--ngx-sidenav-link-item-outline-color-hover`: Defines the outline color of the link item when hovered.
- `--ngx-sidenav-link-item-outline-color-active`: Defines the outline color of the link item when active (commented out).
## SIDENAV CONTENT SCROLLBAR
- `--ngx-sidenav-content-background-color`: Defines the background color of the sidenav content area.
- `--ngx-sidenav-content-background-color-hover`: Defines the background color of the sidenav content area when hovered.
## SIDENAV TOGGLE
- `--ngx-sidenav-toggle-border-color`: Defines the border color of the sidenav toggle.
- `--ngx-sidenav-toggle-background-color`: Defines the background color of the sidenav toggle.
- `--ngx-sidenav-toggle-background-color-hover`: Defines the background color of the sidenav toggle when hovered.
- `--ngx-sidenav-toggle-border-color-hover`: Defines the border color of the sidenav toggle when hovered.
- `--ngx-sidenav-toggle-outline-color`: Defines the outline color of the sidenav toggle.
- `--ngx-sidenav-toggle-icon-color`: Defines the icon color of the sidenav toggle.
## SIDENAV RESIZE HANDLE
- `--ngx-sidenav-resize-handle-indicator-line-background-color`: Defines the background color of the resize handle indicator line.
- `--ngx-sidenav-resize-handle-icon-indicator-line-border-color`: Defines the border color of the resize handle icon indicator line.
- `--ngx-sidenav-resize-handle-icon-indicator-line-color`: Defines the color of the resize handle icon indicator line.
- `--ngx-sidenav-resize-handle-icon-outline-color`: Defines the outline color of the resize handle icon.
- `--ngx-sidenav-resize-handle-indicator-background-color`: Defines the background color of the resize handle indicator.
- `--ngx-sidenav-resize-handle-indicator-background-color-hover`: Defines the background color of the resize handle indicator when hovered.
- `--ngx-sidenav-resize-handle-icon-indicator-background-color`: Defines the background color of the resize handle icon indicator.
- `--ngx-sidenav-resize-handle-icon-indicator-border-color`: Defines the border color of the resize handle icon indicator.
- `--ngx-sidenav-resize-handle-icon-indicator-color`: Defines the color of the resize handle icon indicator.
- `--ngx-sidenav-resize-handle-icon-indicator-background-color-hover`: Defines the background color of the resize handle icon indicator when hovered.
- `--ngx-sidenav-resize-handle-icon-indicator-border-color-hover`: Defines the border color of the resize handle icon indicator when hovered.
- `--ngx-sidenav-resize-handle-icon-indicator-color-hover`: Defines the color of the resize handle icon indicator when hovered.
- `--ngx-sidenav-resize-handle-icon-indicator-line-background-color`: Defines the background color of the resize handle icon indicator line.
## SIDENAV BADGES
- `--badge-class`: Defines the background color for the "class" badge.
- `--badge-constant`: Defines the background color for the "constant" badge.
- `--badge-decorator`: Defines the background color for the "decorator" badge.
- `--badge-directive`: Defines the background color for the "directive" badge.
- `--badge-element`: Defines the background color for the "element" badge.
- `--badge-enum`: Defines the background color for the "enum" badge.
- `--badge-function`: Defines the background color for the "function" badge.
- `--badge-interface`: Defines the background color for the "interface" badge.
- `--badge-pipe`: Defines the background color for the "pipe" badge.
- `--badge-impure-pipe`: Defines the background color for the "impure pipe" badge.
- `--badge-module`: Defines the background color for the "module" badge.
- `--badge-alias`: Defines the background color for the "alias" badge.
- `--badge-block`: Defines the background color for the "block" badge.
- `--badge-deprecated`: Defines the background color for the "deprecated" badge.
- `--badge-custom`: Defines the background color for a custom badge.
## π API Reference
### Components
#### ``
The main sidenav container component.
**Properties:**
- `minWidth: number` - Minimum width (default: 250)
- `maxWidth: number` - Maximum width (default: 600)
- `initialWidth: number` - Initial width (default: 300)
- `collapseWidth: number` - Width when collapsed (default: 30)
- `canResize: boolean` - Enable resizing (default: true)
- `canCollapse: boolean` - Enable collapsing (default: true)
- `position: 'left' | 'right'` - Position (default: 'left')
- `direction: 'ltr' | 'rtl'` - Text direction (default: 'ltr')
- `backdrop: boolean` - Show backdrop (default: false)
- `clearCacheOnReload: boolean` - Clear cache on reload (default: false)
- `menuIconCollapse: string` - Collapse icon (default: 'menu_open')
- `menuIconExpand: string` - Expand icon (default: 'menu')
**Events:**
- `opened()` - Sidenav opened
- `closed()` - Sidenav closed
- `resized(width: number)` - Sidenav resized
#### ``
Menu component for displaying navigation items.
**Properties:**
- `items: StackMenuItem[]` - Menu items array
- `parentLabel: string` - Parent menu label
- `parentBadge: string` - Parent menu badge
- `parentBadgeColor: string` - Parent badge color
### Interfaces
#### `StackMenuItem`
```typescript
interface StackMenuItem {
label: string;
icon?: string;
iconType?: 'material' | 'svg' | 'custom';
route?: string;
children?: StackMenuItem[];
isParent?: boolean;
isTitle?: boolean;
tooltip?: string;
badge?: string | number;
badgeColor?: string;
disabled?: boolean;
summary?: string;
tags?: string[];
[key: string]: unknown; // Custom properties
}
```
#### `MenuStackItem`
```typescript
interface MenuStackItem {
type: 'menu';
title?: string;
badge?: string;
badgeColor?: string;
items: StackMenuItem[];
}
```
#### `ComponentStackItem`
```typescript
interface ComponentStackItem {
type: 'component';
component: Type;
componentData?: Record;
}
```
### SidenavService
The service for programmatic sidenav management.
#### Methods
- `push(item: MenuStackItem | ComponentStackItem): Promise` - Add item to navigation stack
- `pop(): Promise` - Remove current item from stack
- `toggleSidenav(): void` - Toggle sidenav open/closed state
- `setSidenavWidth(width: number): void` - Set sidenav width
- `setConfig(config: SidenavConfig): void` - Configure sidenav settings
- `clearOnNextReload(): void` - Clear state on next page reload
#### Signals
- `isExpanded: Signal` - Sidenav expanded state
- `sidenavWidth: Signal` - Current sidenav width
- `currentMenu: Signal` - Current menu
- `canGoBack: Signal` - Whether back navigation is available
- `minWidth: Signal` - Minimum width
- `maxWidth: Signal` - Maximum width
## π― Advanced Examples
### Custom Component with Data Binding
```typescript
@Component({
selector: 'notification-center',
template: `
Notifications
Mark All Read
@for (notification of notifications(); track notification.id) {
{{ notification.title }}
{{ notification.message }}
{{ notification.timestamp | date:'short' }}
@if (!notification.read) {
Mark Read
}
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NotificationCenterComponent {
readonly notifications = input.required();
markAsRead(id: string) {
// Handle mark as read logic
}
markAllRead() {
// Handle mark all as read logic
}
}
// Usage in parent component
showNotifications() {
const notificationComponent: ComponentStackItem = {
type: 'component',
component: NotificationCenterComponent,
componentData: {
notifications: this.notificationService.getNotifications()
}
};
this.sidenavService.push({ type: 'component', component: notificationComponent});
}
```
### Multi-Level Navigation
```typescript
const complexMenu: MenuStackItem = {
type: 'menu',
title: 'Project Management',
items: [
{
label: 'Projects',
icon: 'folder',
children: [
{
label: 'Active Projects',
children: [
{ label: 'Web App Redesign', route: '/projects/web-redesign' },
{ label: 'Mobile App', route: '/projects/mobile-app' },
{ label: 'API Modernization', route: '/projects/api-modernization' }
]
},
{
label: 'Archived Projects',
children: [
{ label: 'Legacy System', route: '/projects/legacy' },
{ label: 'Old Website', route: '/projects/old-website' }
]
}
]
},
{
label: 'Team',
icon: 'group',
children: [
{ label: 'Developers', route: '/team/developers' },
{ label: 'Designers', route: '/team/designers' },
{ label: 'Project Managers', route: '/team/managers' }
]
}
]
};
```
## πͺ Demo Application
Explore the full functionality in our interactive demo:
**[π Live Demo](https://fsegurai.github.io/ngx-sidenav)**
### Run Demo Locally
```bash
git clone https://github.com/fsegurai/ngx-sidenav.git
cd ngx-sidenav
bun install
bun start
```
The demo showcases:
- All configuration options
- Both HTML and service usage patterns
- Custom component integration
- Multi-level navigation
- Responsive behavior
- Theme customization
## π€ Contributing
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
## π License
This project is licensed under the MIT Licenseβsee the [LICENSE](LICENSE) file for details.