An open API service indexing awesome lists of open source software.

https://github.com/fsegurai/ngx-sidenav

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.

Awesome Lists containing this project

README

          


NGX Sidenav Logo



Build Main Status


Latest Release



GitHub contributors
Dependency status for repo

GitHub License



Stars
Forks

NPM Downloads

`@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: `


{{ title() }}




@for (metric of metrics(); track metric.label) {

{{ metric.label }}
{{ metric.value }}

}



Refresh
Export


`,
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.