A lightweight, multi-calendar Angular date picker supporting Gregorian, Shamsi (Jalali / Persian), and Imperial calendars — with a modern UI, inline year-grid picker, and an optional time picker.
- Three calendar systems: Gregorian · Shamsi (Jalali) · Imperial
- 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)
- RTL ready — Persian month/weekday names built-in
- 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)
Interactive examples with all calendar types, time picker, date restrictions and calendar switcher.
| Peer dependency | Minimum |
|---|---|
@angular/core |
17.0.0 |
@angular/common |
17.0.0 |
@angular/forms |
17.0.0 |
jalali-moment |
3.0.0 |
Angular 17 introduced signal inputs,
input<>(),computed(),effect(), and the@if/@forcontrol-flow syntax that this library depends on.
npm install ng-cyrus-calendar jalali-momentimport { CalendarPopupComponent, CyrusCalendarDirective } from 'ng-cyrus-calendar';
@NgModule({
imports: [
CommonModule,
FormsModule, // or ReactiveFormsModule
CalendarPopupComponent,
CyrusCalendarDirective,
]
})
export class AppModule {}import { CalendarPopupComponent, CyrusCalendarDirective } from 'ng-cyrus-calendar';
@Component({
standalone: true,
imports: [CommonModule, FormsModule, CalendarPopupComponent, CyrusCalendarDirective],
})
export class MyComponent {}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].
<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><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><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 --><input cyrus-calendar [calendar-type]="'shamsi'"
[disable-past-days]="true" [disable-weekends]="true" ... />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 |
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, disable-weekends, disable-past-days |
[calendar-type] |
DatePickerType |
'shamsi' |
Calendar system (ignored when [directive] provided) |
[format] |
string |
'yyyy/MM/dd' |
Display format shown in the input (slashes) |
[value-format] |
string |
'yyyy-MM-dd' |
Structure of the emitted Gregorian date string (e.g. yyyy-MM-dd). Only affects separator/order — the date is always Gregorian regardless of the displayed calendar. |
[time] |
boolean |
false |
Show time picker panel |
[time-format] |
string |
'hh:mm:ss' |
Format for the time part (only when [time]="true") |
[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 to the user. A Shamsi date1404/12/17and an Imperial date2584/12/17both emit2026-03-08. This makes the value safe to send directly to REST APIs and databases without any conversion on your side.
| 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 |
| System | Typical year | Layout | Week start |
|---|---|---|---|
| Gregorian | 2025 | LTR | Monday |
| Shamsi (Jalali) | 1403 | RTL | Saturday |
| Imperial | 2584 | RTL | Saturday |
git clone https://github.com/mhmfofa/cyrus-calendar.git
cd cyrus-calendar
npm install
npm start # dev server → http://localhost:4200
npm run build # production build
npm run build:lib # build the distributable library → dist/cyrus-calendar/# 1. Build
npm run build:lib
# 2. Publish from the dist folder
cd dist/cyrus-calendar
npm publish --access publicMIT © mhmfofa
npm install ng-cyrus-calendarAngular peer requirement:
>=21.0.0
// app.module.ts
import { DatepickerModule } from 'ng-cyrus-calendar';
@NgModule({
imports: [DatepickerModule],
})
export class AppModule {}npm install bootstrap// styles.scss
@import 'bootstrap/dist/css/bootstrap.min.css';<input type="text" #myInput [(ngModel)]="selectedDate" />
<calendar-popup
calendar-type="gregorian"
[(ngModel)]="selectedDate"
[input]="myInput">
</calendar-popup><input type="text" #myInput [(ngModel)]="selectedDate" />
<calendar-popup
calendar-type="shamsi"
[(ngModel)]="selectedDate"
[input]="myInput">
</calendar-popup><input type="text" #myInput [(ngModel)]="selectedDate" />
<calendar-popup
calendar-type="imperial"
[(ngModel)]="selectedDate"
[input]="myInput"
[disable-weekends]="true"
[disable-past-days]="true">
</calendar-popup><calendar-popup
calendar-type="gregorian"
[(ngModel)]="selectedDateTime"
[input]="myInput"
[date]="true"
[time]="true">
</calendar-popup>| Input | Type | Default | Description |
|---|---|---|---|
calendar-type |
'gregorian' | 'shamsi' | 'imperial' |
'shamsi' |
Calendar system to use |
input |
HTMLInputElement |
— | The text input to attach to |
format |
string |
'yyyy/MM/dd' |
Date format string |
date |
boolean |
true |
Show the date picker |
time |
boolean |
false |
Show the time picker |
min |
string |
— | Minimum selectable date (same format) |
max |
string |
— | Maximum selectable date (same format) |
disable-past-days |
boolean |
false |
Disables all past dates |
from-tomorow |
boolean |
false |
Disables today and past dates |
disable-weekends |
boolean |
false |
Disables weekend days |
disables |
(number|string)[] |
— | Array of day-of-week indexes or date strings to disable |
multiple |
boolean |
false |
Allow multi-date selection |
range |
boolean |
false |
Allow date-range selection |
options |
DatePickerOptions |
auto | Override globalization options |
| Token | Meaning | Example |
|---|---|---|
yyyy |
4-digit year | 1403 |
MM |
2-digit month | 07 |
dd |
2-digit day | 05 |
hh |
2-digit hour (24 h) | 14 |
mm |
2-digit minute | 30 |
ss |
2-digit second | 00 |
Clicking the year label in the header opens a 12-year grid overlay. Use › / ‹ to navigate decades. Click any year to select it instantly.
# Clone
git clone https://github.com/mhm/ng-cyrus-calendar.git
cd ng-cyrus-calendar
# Install dependencies
npm install
# Start dev server → http://localhost:4200
npm start
# Production build
npm run build# Builds first (via prepublishOnly script), then publishes
npm publish| System | Year offset | Leap year rule |
|---|---|---|
| Gregorian | — | Standard Gregorian leap year |
| Shamsi (Jalali) | −621 from Gregorian | Iranian solar leap year algorithm |
| Imperial | +1180 from Shamsi | Same as Shamsi |
MIT © mhm