ng-hub-ui-calendar
v21.1.1
Published
Calendar component for Angular applications with multiple views, native drag-and-drop, and event management
Downloads
328
Maintainers
Readme
ng-hub-ui-calendar
⚠️ CRITICAL (MAJOR RELEASE): Version 21.0.0 introduces architectural breaking changes via an SCSS refactor prefixing internal variables to standard (
--hub-calendar-*). Please read the BREAKING_CHANGES.md file before upgrading.
A powerful, flexible calendar component for Angular applications with multiple views, native drag-and-drop event rescheduling, custom templates, and full internationalization support.
🧩 Library Family ng-hub-ui
This library is part of the Hub UI ecosystem:
- ng-hub-ui-accordion
- ng-hub-ui-avatar
- ng-hub-ui-board
- ng-hub-ui-breadcrumbs
- ng-hub-ui-calendar ← You are here
- ng-hub-ui-modal
- ng-hub-ui-paginable
- ng-hub-ui-portal
- ng-hub-ui-stepper
- ng-hub-ui-utils
📑 Table of Contents
✨ Features
- Multiple View Types: Month, Week, Day, and Year views
- Native Drag & Drop: Reschedule events by dragging to different days
- Custom Templates: Full control over event and day cell rendering
- Internationalization: Built-in English and Spanish, extensible for any language
- CSS Variables: Complete styling customization via CSS custom properties
- TypeScript: Full type definitions with CalendarViewType enum
- Standalone Components: Works with modern Angular's standalone architecture
- Accessible: Keyboard navigation and ARIA support
- Lightweight: No external dependencies (native HTML5 drag-and-drop)
📦 Installation
npm install ng-hub-ui-calendar ng-hub-ui-utils🚀 Quick Start
import { Component, signal } from '@angular/core';
import { HubCalendarComponent, CalendarEvent, CalendarViewType } from 'ng-hub-ui-calendar';
@Component({
selector: 'app-calendar-demo',
standalone: true,
imports: [HubCalendarComponent],
template: `
<hub-calendar [events]="events()" [view]="view()" (eventClick)="onEventClick($event)" (dayClick)="onDayClick($event)">
</hub-calendar>
`
})
export class CalendarDemoComponent {
view = signal<CalendarViewType>(CalendarViewType.MONTH);
events = signal<CalendarEvent[]>([
{
id: '1',
title: 'Team Meeting',
start: new Date(),
end: new Date(Date.now() + 2 * 60 * 60 * 1000)
}
]);
onEventClick(event: CalendarEvent): void {
console.log('Event clicked:', event);
}
onDayClick(day: CalendarDay): void {
console.log('Day clicked:', day);
}
}📚 Examples
Basic Calendar
import { HubCalendarComponent, CalendarEvent } from 'ng-hub-ui-calendar';
@Component({
standalone: true,
imports: [HubCalendarComponent],
template: `<hub-calendar [events]="events()"></hub-calendar>`
})
export class BasicCalendarComponent {
events = signal<CalendarEvent[]>([
{ id: '1', title: 'Meeting', start: new Date() },
{ id: '2', title: 'Lunch', start: new Date(), allDay: true }
]);
}View Types
import { CalendarViewType } from 'ng-hub-ui-calendar';
@Component({
template: `
<hub-calendar [events]="events()" [view]="currentView()" (viewChange)="currentView.set($event)"> </hub-calendar>
<div class="controls">
<button (click)="currentView.set(CalendarViewType.MONTH)">Month</button>
<button (click)="currentView.set(CalendarViewType.WEEK)">Week</button>
<button (click)="currentView.set(CalendarViewType.DAY)">Day</button>
<button (click)="currentView.set(CalendarViewType.YEAR)">Year</button>
</div>
`
})
export class ViewTypesComponent {
CalendarViewType = CalendarViewType;
currentView = signal<CalendarViewType>(CalendarViewType.MONTH);
}Custom Templates
import { HubCalendarComponent, EventTemplateDirective, DayCellTemplateDirective } from 'ng-hub-ui-calendar';
@Component({
standalone: true,
imports: [HubCalendarComponent, EventTemplateDirective, DayCellTemplateDirective],
template: `
<hub-calendar [events]="events()">
<!-- Custom Event Template -->
<ng-template eventTpt let-event="event">
<div class="custom-event" [class.important]="event.data?.important">
<span class="icon">{{ event.data?.important ? '⭐' : '📅' }}</span>
<span>{{ event.title }}</span>
</div>
</ng-template>
<!-- Custom Day Cell Template -->
<ng-template dayCellTpt let-day="day">
<div class="custom-day">
<span class="day-number">{{ day.date | date: 'd' }}</span>
@if (day.events.length > 0) {
<span class="badge">{{ day.events.length }}</span>
}
</div>
</ng-template>
</hub-calendar>
`
})
export class CustomTemplatesComponent {
events = signal<CalendarEvent<{ important: boolean }>>([
{ id: '1', title: 'VIP Meeting', start: new Date(), data: { important: true } },
{ id: '2', title: 'Regular Task', start: new Date(), data: { important: false } }
]);
}Drag and Drop
@Component({
template: `
<hub-calendar [events]="events()" [config]="{ dragAndDropEnabled: true }" (eventDrop)="onEventDrop($event)">
</hub-calendar>
`
})
export class DragDropComponent {
events = signal<CalendarEvent[]>([{ id: '1', title: 'Movable Event', start: new Date() }]);
onEventDrop(event: { event: CalendarEvent; newDate: Date; previousDate: Date }): void {
console.log(`Moved "${event.event.title}" from ${event.previousDate} to ${event.newDate}`);
// Update the event in your data
this.events.update((events) => events.map((e) => (e.id === event.event.id ? { ...e, start: event.newDate } : e)));
}
}Configuration
import { CalendarConfig, CalendarViewType } from 'ng-hub-ui-calendar';
@Component({
template: ` <hub-calendar [events]="events()" [config]="calendarConfig" [weekStartsOn]="1"> </hub-calendar> `
})
export class ConfigurationComponent {
calendarConfig: CalendarConfig = {
initialView: CalendarViewType.WEEK,
weekStartsOn: 1, // Monday
showWeekNumbers: true,
dayStartHour: 8,
dayEndHour: 18,
slotDuration: 30,
availableViews: [CalendarViewType.MONTH, CalendarViewType.WEEK, CalendarViewType.DAY],
dragAndDropEnabled: true,
eventCreationEnabled: true
};
}Internationalization
// Using built-in translations
@Component({
template: ` <hub-calendar [events]="events()" [locale]="'es'"> </hub-calendar> `
})
export class I18nComponent {}
// With HubTranslationService
// Add calendar translations to your i18n files:
// {
// "calendar": {
// "weekdays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
// "months": ["January", "February", ...],
// "today": "Today",
// "previous": "Previous",
// "next": "Next"
// }
// }Event Handling
@Component({
template: `
<hub-calendar
[events]="events()"
[(view)]="currentView"
[(selectedDate)]="selectedDate"
(eventClick)="onEventClick($event)"
(dayClick)="onDayClick($event)"
(eventDrop)="onEventDrop($event)"
(viewChange)="onViewChange($event)"
(dateChange)="onDateChange($event)"
>
</hub-calendar>
`
})
export class EventHandlingComponent {
currentView = signal<CalendarViewType>(CalendarViewType.MONTH);
selectedDate = signal<Date>(new Date());
onEventClick(event: CalendarEvent): void {
// Open event details modal
}
onDayClick(day: CalendarDay): void {
// Create new event on this day
}
onEventDrop(data: { event: CalendarEvent; newDate: Date; previousDate: Date }): void {
// Update event date in backend
}
onViewChange(view: CalendarViewType): void {
// Track view analytics
}
onDateChange(date: Date): void {
// Load events for new date range
}
}📖 API Reference
Inputs
| Input | Type | Default | Description |
| -------------- | -------------------- | ------------ | ---------------------------------------- |
| events | CalendarEvent[] | [] | Events to display on the calendar |
| view | CalendarViewType | MONTH | Current view type (two-way bindable) |
| selectedDate | Date | new Date() | Selected/focused date (two-way bindable) |
| config | CalendarConfig | {} | Configuration options |
| eventClass | string \| Function | - | CSS class(es) for events |
| weekStartsOn | 0-6 | 0 | Day week starts on (0=Sunday) |
| locale | string | 'en' | Language code for translations |
Outputs
| Output | Type | Description |
| ------------ | ---------------------------------- | ---------------------------------------- |
| eventClick | CalendarEvent | Emitted when an event is clicked |
| dayClick | CalendarDay | Emitted when a day cell is clicked |
| eventDrop | { event, newDate, previousDate } | Emitted when an event is dropped |
| viewChange | CalendarViewType | Emitted when view type changes |
| dateChange | Date | Emitted when navigation changes the date |
Interfaces
interface CalendarEvent<T = any> {
id?: number | string;
title: string;
description?: string;
start: Date;
end?: Date;
allDay?: boolean;
cssClass?: string | ((event: CalendarEvent<T>) => string);
data?: T;
}
interface CalendarDay<T = any> {
date: Date;
events: CalendarEvent<T>[];
isToday: boolean;
isCurrentMonth: boolean;
isWeekend: boolean;
isSelected?: boolean;
}
enum CalendarViewType {
MONTH = 'month',
WEEK = 'week',
DAY = 'day',
YEAR = 'year'
}
interface CalendarConfig {
initialView?: CalendarViewType;
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
showWeekNumbers?: boolean;
dayStartHour?: number;
dayEndHour?: number;
slotDuration?: number;
availableViews?: CalendarViewType[];
dragAndDropEnabled?: boolean;
eventCreationEnabled?: boolean;
}🎨 Styling
Full CSS variable catalog:
Framework-agnostic customization example:
hub-calendar {
--hub-calendar-bg: #ffffff;
--hub-calendar-border-color: #d0d7de;
--hub-calendar-btn-active-bg: #0d6efd;
--hub-calendar-event-bg: #2563eb;
}Bootstrap integration example (optional):
hub-calendar {
--hub-calendar-bg: var(--bs-body-bg);
--hub-calendar-color: var(--bs-body-color);
--hub-calendar-border-color: var(--bs-border-color);
--hub-calendar-btn-active-bg: var(--bs-primary);
}📞 Support & License
- Issues: GitHub Issues
- Author: Carlos Morcillo
- License: MIT
Made with ❤️ by the Hub UI team
