Sitelet https://github.com/mhmfofa/cyrus-calendar
Skip to content

Repository files navigation

ng-cyrus-calendar

A lightweight, multi-calendar Angular date picker supporting Gregorian, Shamsi (Jalali / Persian), Imperial, and Hijri (Islamic) calendars — with a modern UI, inline year-grid picker, and an optional time picker.


Features

  • Four calendar systems: Gregorian · Shamsi (Jalali) · Imperial · Hijri (Islamic / Umm al-Qura)
  • Year-grid picker: click the year to browse and select from a 12-year grid
  • Month-grid picker: full month overlay
  • Disable rules: past days, weekends, specific dates, or a custom list
  • Date ranges & multi-select
  • Optional time picker (hours · minutes · seconds)
  • Configurable popup placement — six positions relative to the attached input
  • Light, dark, and system themes controlled through an ancestor data-theme attribute
  • RTL ready — Persian and Arabic month/weekday names built-in; Hijri uses Sunday-first week with Friday/Saturday weekends
  • Keyboard-accessible popup controls with labeled navigation and time inputs
  • Separate display vs. value format — show slashes to the user, store hyphens for APIs
  • No jQuery — pure Angular + Bootstrap 5
  • Signal-based state, Angular control-flow syntax (@if, @for)

Live Demo

http://calendar.molayemi.com

Interactive examples with all calendar types, time picker, date restrictions and calendar switcher.


Requirements

Peer dependency Minimum Notes
@angular/core 17.0.0
@angular/common 17.0.0
@angular/forms 17.0.0
jalaali-js ^2.0.1 Required for Shamsi & Imperial calendars
moment-hijri ^3.0.0 Required for Hijri calendar

Angular 17 introduced signal inputs, input<>(), computed(), effect(), and the @if/@for control-flow syntax that this library depends on.


Installation

npm install ng-cyrus-calendar

# Shamsi (Jalali) and Imperial calendars
npm install jalaali-js@^2.0.1

# Hijri (Islamic) calendar
npm install moment-hijri@^3.0.0

# To support all calendar types
npm install jalaali-js@^2.0.1 moment-hijri@^3.0.0

Note: In the current 1.1.x package, both calendar libraries are statically imported. Install both packages if your build reports a missing-module error, even when your app uses only one calendar type.


Setup

Standalone component

import { CalendarPopupComponent, CyrusCalendarDirective } from 'ng-cyrus-calendar';

@Component({
  standalone: true,
  imports: [CommonModule, FormsModule, CalendarPopupComponent, CyrusCalendarDirective],
})
export class MyComponent {}

NgModule-based app

import { CalendarPopupComponent, CyrusCalendarDirective } from 'ng-cyrus-calendar';

@NgModule({
  imports: [CommonModule, FormsModule, CalendarPopupComponent, CyrusCalendarDirective]
})
export class AppModule {}

Usage

Add the cyrus-calendar directive to any <input> and place a <calendar-popup> next to it. Export the directive as a template reference (#cal="cyrusCalendar") and pass it to the popup via [directive].

Shamsi (Jalali / Persian)

<input type="text" #myInput #cal="cyrusCalendar"
  cyrus-calendar [calendar-type]="'shamsi'"
  autocomplete="off" inputmode="none" />
<calendar-popup [input]="myInput" [directive]="cal" [(ngModel)]="selectedDate">
</calendar-popup>

Gregorian

<input type="text" #myInput #cal="cyrusCalendar"
  cyrus-calendar [calendar-type]="'gregorian'"
  autocomplete="off" inputmode="none" />
<calendar-popup [input]="myInput" [directive]="cal" [(ngModel)]="selectedDate">
</calendar-popup>

Imperial

<input type="text" #myInput #cal="cyrusCalendar"
  cyrus-calendar [calendar-type]="'imperial'"
  autocomplete="off" inputmode="none" />
<calendar-popup [input]="myInput" [directive]="cal" [(ngModel)]="selectedDate">
</calendar-popup>

Hijri (Islamic)

Requires moment-hijri to be installed.

<input type="text" #myInput #cal="cyrusCalendar"
  cyrus-calendar [calendar-type]="'hijri'"
  autocomplete="off" inputmode="none" />
<calendar-popup [input]="myInput" [directive]="cal" [(ngModel)]="selectedDate">
</calendar-popup>

With time picker

<calendar-popup
  [input]="myInput"
  [directive]="cal"
  [time]="true"
  [(ngModel)]="selectedDateTime">
</calendar-popup>
<!-- Value emitted : 1403-06-15T14:30:00  -->
<!-- Input displays: 1403/06/15 - 14:30:00 -->

Placement and theme

The popup defaults to bottom-left. Choose top, top-left, top-right, bottom, bottom-left, or bottom-right; the bare top and bottom placements center the popup horizontally.

Theme is controlled with CSS, not a component input. Set data-theme on an ancestor of the popup to light, dark, or system. The system value follows the user's prefers-color-scheme setting.

<div data-theme="system">
  <input type="text" #myInput #cal="cyrusCalendar"
    cyrus-calendar [calendar-type]="'gregorian'"
    autocomplete="off" inputmode="none" />
  <calendar-popup
    [input]="myInput"
    [directive]="cal"
    placement="top-right"
    [(ngModel)]="selectedDate">
  </calendar-popup>
</div>

Calendar switcher (value preserved on type change)

calendarType = signal<DatePickerType>(DatePickerType.Imperial);
<input type="text" #myInput #cal="cyrusCalendar"
  cyrus-calendar [calendar-type]="calendarType()"
  autocomplete="off" inputmode="none" />
<calendar-popup [input]="myInput" [directive]="cal" [(ngModel)]="value">
</calendar-popup>

⚠️ The emitted value is always in the Gregorian calendar, regardless of the calendar type displayed. A Shamsi date 1404/12/17 and an Imperial date 2584/12/17 both emit 2026-03-08. This makes the value safe to send directly to REST APIs and databases without any conversion.


API Reference

Directive: cyrus-calendar

Apply to <input>. Export as #ref="cyrusCalendar" to pass to <calendar-popup [directive]="ref">.

Input Type Default Description
[calendar-type] DatePickerType 'imperial' Active calendar system
[disable-weekends] boolean false Disable weekend days
[disable-past-days] boolean false Disable dates before today
[placeholder] string auto Custom placeholder text

Component: <calendar-popup>

Implements ControlValueAccessor — works with ngModel and reactive forms.

Input Type Default Description
[input] HTMLInputElement required Template reference of the attached input
[directive] CyrusCalendarDirective null Directive reference — inherits calendar-type and disable rules
[calendar-type] DatePickerType 'shamsi' Calendar system (ignored when [directive] provided)
[placement] DatePickerPlacement 'bottom-left' Popup placement: top, top-left, top-right, bottom, bottom-left, or bottom-right; bare top/bottom are centered
[format] string 'yyyy/MM/dd' Display format shown in the input
[value-format] string 'yyyy-MM-dd' Format of the emitted Gregorian date string
[time] boolean false Show time picker panel
[time-format] string 'hh:mm:ss' Format for the time part
[date] boolean true Show date picker panel
[min] string null Minimum selectable date
[max] string null Maximum selectable date
[disable-past-days] boolean false Disable past dates
[from-tomorow] boolean false Only allow tomorrow onwards
[disable-weekends] boolean false Disable weekend days
[multiple] boolean false Multi-date selection
[range] boolean false Date-range selection
[options] DatePickerOptions — Advanced configuration object

⚠️ The emitted value is always in the Gregorian calendar, regardless of the calendar type displayed. A Shamsi date 1404/12/17 and an Imperial date 2584/12/17 both emit 2026-03-08.


Format Tokens

Token Meaning Example
yyyy 4-digit year 1403, 2025
MM 2-digit month (zero-padded) 07
dd 2-digit day (zero-padded) 05
hh Hour 0–23 (zero-padded) 14
mm Minute (zero-padded) 30
ss Second (zero-padded) 00

Calendar System Notes

System Typical year Layout Week start Weekends
Gregorian 2025 LTR Monday Sat + Sun
Shamsi (Jalali) 1403 RTL Saturday Friday
Imperial 2584 RTL Saturday Friday
Hijri (Islamic) 1446 RTL Sunday Fri + Sat

Development

git clone https://github.com/mhmfofa/cyrus-calendar.git
cd cyrus-calendar
npm install
npm start          # dev server → http://localhost:4200
npm run build:lib  # build the distributable library → dist/cyrus-calendar/

Publishing to npm

# 1. Build the library
npm run build:lib

# 2. Publish from the dist folder (NOT the root)
cd dist/cyrus-calendar
npm publish --access public

See NPM-PUBLISH.md for the full publishing guide.


Changelog

See CHANGELOG.md for the full version history.


License

MIT © mhmfofa

| [disable-past-days] | boolean | false | Disable past dates | | [from-tomorow] | boolean | false | Only allow tomorrow onwards | | [disable-weekends] | boolean | false | Disable weekend days | | [multiple] | boolean | false | Multi-date selection | | [range] | boolean | false | Date-range selection | | [options] | DatePickerOptions | — | Advanced configuration object |


Format Tokens

Token Meaning Example
yyyy 4-digit year 1403, 2025
MM 2-digit month (zero-padded) 07
dd 2-digit day (zero-padded) 05
hh Hour 0–23 (zero-padded) 14
mm Minute (zero-padded) 30
ss Second (zero-padded) 00

Calendar System Notes

System Typical year Layout Week start Weekends
Gregorian 2025 LTR Monday Sat + Sun
Shamsi (Jalali) 1403 RTL Saturday Friday
Imperial 2584 RTL Saturday Friday
Hijri (Islamic) 1446 RTL Sunday Fri + Sat

Development

git clone https://github.com/mhmfofa/cyrus-calendar.git
cd cyrus-calendar
npm install
npm start          # dev server → http://localhost:4200
npm run build:lib  # build the distributable library → dist/cyrus-calendar/

Publishing to npm

# 1. Build the library
npm run build:lib

# 2. Publish from the dist folder (NOT the root)
cd dist/cyrus-calendar
npm publish --access public

See NPM-PUBLISH.md for the full publishing guide.


Changelog

See CHANGELOG.md for the full version history.


License

MIT © mhmfofa

About

Angular date/time picker library with Shamsi, Gregorian and Imperial calendar support

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages