import { Component } from '@angular/core';
import { WrEventCalendar } from 'ngwr/event-calendar';
@Component({ imports: [WrEventCalendar] })
export class MyComponent {}Event calendar
Month, week and day views of events the user can move and resize.
Installation
Import the class, and @use the entry point in your global styles. Nothing warns you when the @use is missing.
Date adapter
Uses LOCALE_ID with no provider; for another date library, pass a WrDateAdapter subclass (Configuration).
// Only for another date library:
import { provideWr } from 'ngwr';
import { withDates } from 'ngwr/date';
bootstrapApplication(App, { providers: [provideWr(withDates({ adapter: AppDateAdapter }))] });Views
view and date are two-way. To use your own toolbar, bind them and set hideHeader.
<wr-event-calendar [events]="events()" [(view)]="view" [(date)]="anchor" />Events
end is exclusive. color takes any intent; editable: false locks one event.
protected readonly events = signal<readonly WrCalendarEvent[]>([
{ id: 1, title: 'Design review', start: at(0, 10), end: at(0, 11, 30), color: 'primary' },
{ id: 5, title: 'Conference', start: at(2, 0), end: at(5, 0), allDay: true, color: 'info' },
{ id: 7, title: 'Frozen — no deploys', start: at(6, 0), end: at(7, 0), allDay: true, editable: false },
]);Drag to move and resize
Set editable. The calendar never changes events: apply eventChange to your own state, or ignore it to cancel the drag.
<wr-event-calendar
editable
[events]="events()"
[(view)]="view"
[(date)]="anchor"
(eventChange)="apply($event)"
/>protected apply(change: WrCalendarEventChange): void {
this.events.update(events =>
events.map(event =>
event.id === change.event.id ? { ...event, start: change.start, end: change.end } : event
)
);
}The time grid
dayStartHour and dayEndHour trim the visible band. slotMinutes sets both the row height and the drag snap.
<wr-event-calendar
view="week"
[slotMinutes]="15"
[dayStartHour]="9"
[dayEndHour]="14"
[events]="events()"
/>Creating from empty space
A click on an empty slot, or Enter on an empty cell, emits slotClick.
<wr-event-calendar [events]="events()" (slotClick)="compose($event)" />Custom chip contents
<ng-template wrCalendarEvent> replaces a chip's content. Add WrCalendarEventTemplate to imports, or the template is ignored.
<!-- imports: [WrEventCalendar, WrCalendarEventTemplate] -->
<wr-event-calendar [events]="events()">
<ng-template wrCalendarEvent let-event>
<strong>{{ event.title }}</strong>
<small>{{ event.data.room }}</small>
</ng-template>
</wr-event-calendar>Keyboard
The grid is one tab stop; each chip is its own.
| Key | Does |
|---|---|
| Previous or next day. | |
| One week in month view, one slot in week and day view. | |
| First / last day of the current week row. | |
Emits slotClick on an empty cell, or focuses the first chip. |
| Key | Does |
|---|---|
| Back to the cell the chip lives in. | |
Moves the event. Emits eventChange with kind: 'move'. | |
Moves the end only. Emits eventChange with kind: 'resize'. |
Chip keys need editable and skip events with editable: false.
API
| Name | Description | Type | Default |
|---|---|---|---|
events | Everything to render. Never mutated — see eventChange. | readonly WrCalendarEvent[] | [] |
view | Which span is shown. Two-way bindable. | WrCalendarView | 'month' |
date | Any date inside the shown span. Two-way bindable. | Date | new Date() |
views | Which buttons the view switcher offers. Empty hides it. | readonly WrCalendarView[] | ['month', 'week', 'day'] |
editable | Allow dragging chips to move and resize them. | boolean | false |
slotMinutes | Minutes per row in the time views — also the drag snap. | number | 30 |
dayStartHour | First hour the time views show. | number | 0 |
dayEndHour | First hour they do NOT show, exclusive. | number | 24 |
maxLanes | Lanes a month cell shows before collapsing the rest into “+N more”. | number | 3 |
hideHeader | Hide the built-in header — supply your own navigation instead. | boolean | false |
(eventClick) | A chip was activated. | WrCalendarEvent | — |
(slotClick) | Empty space was activated — the slot the user pointed at. | WrCalendarSlot | — |
(eventChange) | A drag or an Alt + arrow finished. Apply it yourself; nothing moves until you do. | WrCalendarEventChange | — |
ariaLabel | Accessible name of the grid; overridable for a page with several. | string | null | null |
CSS variables
Set these on the element itself, with a rule more specific than its Declared on selector. In a global stylesheet, put a class of yours on an ancestor it really has: <body> for an overlay panel, which renders outside your markup. In a component stylesheet the selector alone works, but only for an element in that component's own template. A value on a wrapper or :root is shadowed, because ngwr/event-calendar declares each default on its own element.
| Variable | Default | Declared on |
|---|---|---|
--wr-event-calendar-band-height | 1.25rem | .wr-event-calendar |
--wr-event-calendar-cell-padding | var(--wr-space-xs) | .wr-event-calendar__cell |
--wr-event-calendar-chip-font-size | var(--wr-text-xs) | .wr-event-calendar__chip |
--wr-event-calendar-chip-gap | var(--wr-space-xs) | .wr-event-calendar |
--wr-event-calendar-chip-inline-gap | var(--wr-space-xs) | .wr-event-calendar__chip |
--wr-event-calendar-chip-inset | 0.125rem | .wr-event-calendar |
--wr-event-calendar-chip-padding-x | var(--wr-space-sm) | .wr-event-calendar__chip +1 variant override |
--wr-event-calendar-chip-padding-y | 0 | .wr-event-calendar__chip +1 variant override |
--wr-event-calendar-chip-radius | calc(var(--wr-border-radius-sm) / 2) | .wr-event-calendar |
--wr-event-calendar-chip-time-font-weight | var(--wr-font-weight-medium) | .wr-event-calendar__chip-time |
--wr-event-calendar-colhead-day-font-size | var(--wr-text-base) | .wr-event-calendar__colhead-day |
--wr-event-calendar-colhead-day-font-weight | var(--wr-font-weight-semibold) | .wr-event-calendar__colhead-day |
--wr-event-calendar-colhead-font-size | var(--wr-text-xs) | .wr-event-calendar__colhead |
--wr-event-calendar-colhead-font-weight | var(--wr-font-weight-medium) | .wr-event-calendar__colhead |
--wr-event-calendar-colhead-gap | var(--wr-space-xs) | .wr-event-calendar__colhead |
--wr-event-calendar-colhead-padding | var(--wr-space-sm) | .wr-event-calendar__colhead |
--wr-event-calendar-cols | 7 | .wr-event-calendar |
--wr-event-calendar-daynum-font-size | var(--wr-text-sm) | .wr-event-calendar__daynum |
--wr-event-calendar-daynum-radius | var(--wr-border-radius-pill) | .wr-event-calendar__daynum |
--wr-event-calendar-fill | var(--wr-color-fill) | .wr-event-calendar |
--wr-event-calendar-gap | var(--wr-space-md) | .wr-event-calendar |
--wr-event-calendar-grid-radius | var(--wr-border-radius-base) | .wr-event-calendar__grid |
--wr-event-calendar-gutter | 3.75rem | .wr-event-calendar |
--wr-event-calendar-gutter-font-size | var(--wr-text-xs) | .wr-event-calendar__gutter |
--wr-event-calendar-gutter-padding-x | var(--wr-space-sm) | .wr-event-calendar__gutter |
--wr-event-calendar-header-column-gap | var(--wr-space-md) | .wr-event-calendar__header |
--wr-event-calendar-header-row-gap | var(--wr-space-sm) | .wr-event-calendar__header |
--wr-event-calendar-line | var(--wr-border-base) | .wr-event-calendar |
--wr-event-calendar-more-font-size | var(--wr-text-xs) | .wr-event-calendar__more |
--wr-event-calendar-more-padding-x | var(--wr-space-sm) | .wr-event-calendar__more |
--wr-event-calendar-more-radius | var(--wr-border-radius-sm) | .wr-event-calendar__more |
--wr-event-calendar-nav-gap | var(--wr-space-xs) | .wr-event-calendar__nav |
--wr-event-calendar-slot-height | 1.5rem | .wr-event-calendar |
--wr-event-calendar-title-font-size | var(--wr-text-lg) | .wr-event-calendar__title |
--wr-event-calendar-title-font-weight | var(--wr-font-weight-semibold) | .wr-event-calendar__title |
Dependencies
| Built on | Button, ngwr/date |
|---|