A modern, customizable Persian (Jalali) date picker web component with framework integrations.
- 🎨 Fully customizable with CSS variables
- 🌙 Dark mode support
- 📱 Mobile-friendly with touch gestures
- 🎯 Framework integrations (React, Vue, Angular)
- 📅 Holiday support with multiple event types (Iran, Afghanistan, Ancient Iran, International)
- 🔄 RTL support
- 🎨 Multiple theme options
- 📦 Zero dependencies
- 🎯 TypeScript support
- 📊 Range selection mode
- 🚫 Disabled dates support
- 🎨 Customizable UI elements visibility
npm install persian-datepicker-element
# or
yarn add persian-datepicker-element
# or
pnpm add persian-datepicker-element
npm install react-persian-datepicker-element persian-datepicker-element
# or
yarn add react-persian-datepicker-element persian-datepicker-element
# or
pnpm add react-persian-datepicker-element persian-datepicker-element
npm install vue-persian-datepicker-element persian-datepicker-element
# or
yarn add vue-persian-datepicker-element persian-datepicker-element
# or
pnpm add vue-persian-datepicker-element persian-datepicker-element
npm install ngx-persian-datepicker-element persian-datepicker-element
# or
yarn add ngx-persian-datepicker-element persian-datepicker-element
# or
pnpm add ngx-persian-datepicker-element persian-datepicker-element
<!-- Import the component -->
<script type="module" src="node_modules/persian-datepicker-element/dist/persian-datepicker-element.min.js"></script>
<!-- Use the component -->
<persian-datepicker-element
placeholder="انتخاب تاریخ"
format="YYYY/MM/DD"
show-holidays
rtl
></persian-datepicker-element>
import { PersianDatepicker } from 'react-persian-datepicker-element';
function App() {
const handleChange = (event) => {
console.log('تاریخ انتخاب شده:', event.detail);
};
return (
<PersianDatepicker
placeholder="انتخاب تاریخ"
format="YYYY/MM/DD"
showEvents
rtl
onChange={handleChange}
/>
);
}
<template>
<PersianDatepicker
placeholder="انتخاب تاریخ"
format="YYYY/MM/DD"
:show-holidays="true"
:rtl="true"
@change="handleChange"
/>
</template>
<script setup>
import { PersianDatepicker } from 'vue-persian-datepicker-element';
const handleChange = (event) => {
console.log('تاریخ انتخاب شده:', event.detail);
};
</script>
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgxPersianDatepickerModule } from 'ngx-persian-datepicker-element';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
NgxPersianDatepickerModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<ngx-persian-datepicker-element
placeholder="انتخاب تاریخ"
format="YYYY/MM/DD"
[showEvents]="true"
[rtl]="true"
(dateChange)="onDateChange($event)"
></ngx-persian-datepicker-element>
`
})
export class AppComponent {
onDateChange(event: any) {
console.log('تاریخ شمسی:', event.jalali); // [year, month, day]
console.log('تاریخ میلادی:', event.gregorian);
console.log('آیا تعطیل است:', event.isHoliday);
console.log('رویدادها:', event.events);
}
}
// app.component.ts
import { Component } from '@angular/core';
import { NgxPersianDatepickerComponent } from 'ngx-persian-datepicker-element';
@Component({
selector: 'app-root',
standalone: true,
imports: [NgxPersianDatepickerComponent],
template: `
<ngx-persian-datepicker-element
placeholder="تاریخ را انتخاب کنید"
format="YYYY/MM/DD"
[showEvents]="true"
(dateChange)="onDateChange($event)"
></ngx-persian-datepicker-element>
`
})
export class AppComponent {
onDateChange(event: any) {
console.log('تاریخ شمسی:', event.jalali); // [سال, ماه, روز]
console.log('تاریخ میلادی:', event.gregorian);
console.log('آیا تعطیل است:', event.isHoliday);
console.log('رویدادها:', event.events);
}
}
// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { NgxPersianDatepickerComponent } from 'ngx-persian-datepicker-element';
@Component({
selector: 'app-root',
standalone: true,
imports: [NgxPersianDatepickerComponent, ReactiveFormsModule],
template: `
<form [formGroup]="dateForm">
<ngx-persian-datepicker-element
formControlName="date"
placeholder="تاریخ را انتخاب کنید"
format="YYYY/MM/DD">
</ngx-persian-datepicker-element>
</form>
`
})
export class AppComponent {
dateForm: FormGroup;
constructor(private fb: FormBuilder) {
this.dateForm = this.fb.group({
date: [1403, 6, 15] // Initial value: [year, month, day]
});
}
}
Prop/Attribute | Type | Default | Description |
---|---|---|---|
value | string | [number, number, number] | - | The selected date value |
placeholder | string | - | Placeholder text |
format | string | "YYYY/MM/DD" | Date format string |
show-holidays | boolean | false | Show holiday indicators |
holiday-types | string | "Iran,Afghanistan,AncientIran,International" | Comma-separated list of holiday types to display. Use "all" to show all available holiday types |
rtl | boolean | false | Right-to-left layout |
min-date | [number, number, number] | - | Minimum selectable date |
max-date | [number, number, number] | - | Maximum selectable date |
disabled-dates | string | - | The name of a function that determines if a date should be disabled |
disabled | boolean | false | Disable the datepicker |
dark-mode | boolean | false | Enable dark mode |
range-mode | boolean | false | Enable date range selection mode |
show-month-selector | boolean | true | Show month selector dropdown |
show-year-selector | boolean | true | Show year selector dropdown |
show-prev-button | boolean | true | Show previous month button |
show-next-button | boolean | true | Show next month button |
show-today-button | boolean | true | Show today button |
show-tomorrow-button | boolean | true | Show tomorrow button |
today-button-text | string | "امروز" | Custom text for today button |
tomorrow-button-text | string | "فردا" | Custom text for tomorrow button |
today-button-class | string | "" | Additional CSS classes for today button |
tomorrow-button-class | string | "" | Additional CSS classes for tomorrow button |
Event | Detail Type | Description |
---|---|---|
change | { jalali: [number, number, number], gregorian: [number, number, number], isHoliday: boolean, events: Array, formattedDate: string, isoString: string } | Fired when a date is selected |
change | { range: { start: [number, number, number], end: [number, number, number], startISOString: string, endISOString: string, startGregorian: [number, number, number], endGregorian: [number, number, number] }, isRange: true } | Fired when a date range is selected (in range mode) |
datepicker.addEventListener('change', (event) => {
// ISO string for the selected date
console.log('Selected date ISO string:', event.detail.isoString);
// Access ISO strings from events (like holidays)
if (event.detail.events.length > 0) {
event.detail.events.forEach(eventItem => {
console.log(`Event: ${eventItem.title}, ISO date: ${eventItem.isoString}`);
});
}
});
rangePicker.addEventListener('change', (event) => {
if (event.detail.isRange) {
// ISO strings for range start and end
console.log('Range start ISO:', event.detail.range.startISOString);
console.log('Range end ISO:', event.detail.range.endISOString);
}
});
Method | Parameters | Return Type | Description |
---|---|---|---|
setValue | (year: number, month: number, day: number) | void | Sets the datepicker value |
getValue | () | [number, number, number] | null | Gets the current selected date as a tuple |
open | () | void | Opens the datepicker calendar |
close | () | void | Closes the datepicker calendar |
setMinDate | (year: number, month: number, day: number) | void | Sets the minimum allowed date |
setMaxDate | (year: number, month: number, day: number) | void | Sets the maximum allowed date |
setDisabledDatesFn | (fn: (year: number, month: number, day: number) => boolean) | void | Sets a function to determine disabled dates |
setRange | (start: [number, number, number], end: [number, number, number]) | void | Sets a date range (in range mode) |
getRange | () | { start: [number, number, number] | null, end: [number, number, number] | null } | Gets the current selected range |
clear | () | void | Clears the selected date or range |
seteventTypes | (types: string | string[]) | void | Sets the holiday types to display |
geteventTypes | () | string[] | Gets the current holiday types |
isShowingAllTypes | () | boolean | Checks if all holiday types are being shown |
isSelectedDateHoliday | () | boolean | Checks if the currently selected date is a holiday |
getSelectedDateEvents | () | any[] | Gets events for the currently selected date |
To enable date range selection mode:
<persian-datepicker-element range-mode></persian-datepicker-element>
In React:
<PersianDatepicker rangeMode />
In Vue:
<PersianDatepicker :range-mode="true" />
In Angular:
<ngx-persian-datepicker-element [rangeMode]="true"></ngx-persian-datepicker-element>
You can control the visibility of various UI elements:
<persian-datepicker-element
show-month-selector="false"
show-year-selector="true"
show-prev-button="true"
show-next-button="true"
show-today-button="false"
show-tomorrow-button="true"
></persian-datepicker-element>
<persian-datepicker-element
today-button-text="Go to Today"
tomorrow-button-text="Next Day"
today-button-class="primary rounded"
tomorrow-button-class="secondary rounded"
></persian-datepicker-element>
<persian-datepicker-element dark-mode></persian-datepicker-element>
There are three ways to specify which dates should be disabled:
Define a function in the global scope and reference it by name:
<script>
function isWeekend(year, month, day) {
const date = new Date(year, month - 1, day);
const dayOfWeek = date.getDay();
return dayOfWeek === 5 || dayOfWeek === 6; // Disable Friday and Saturday (Persian weekend)
}
</script>
<persian-datepicker-element disabled-dates="isWeekend"></persian-datepicker-element>
Define a method directly on the element after retrieving it:
<persian-datepicker-element id="my-picker"></persian-datepicker-element>
<script>
const picker = document.getElementById('my-picker');
// Add a method to the element
picker.isHoliday = function(year, month, day) {
// Custom logic to determine holidays
return day === 13; // Disable 13th of each month as an example
};
// Reference the method by name
picker.setAttribute('disabled-dates', 'isHoliday');
</script>
For React, Vue, or other framework users, you can pass a function directly:
// React example
import { PersianDatepicker } from 'react-persian-datepicker-element';
function App() {
// Define the function locally
const isEvenDay = (year, month, day) => {
return day % 2 === 0; // Disable even days
};
return (
<PersianDatepicker
placeholder="Select date"
disabledDates={isEvenDay}
/>
);
}
You can also use the setDisabledDatesFn
method directly:
const picker = document.getElementById('my-picker');
picker.setDisabledDatesFn((year, month, day) => {
return day % 2 === 0; // Disable even days
});
- Full TypeScript support
- Ref forwarding for imperative methods
- React event handling
- Controlled and uncontrolled modes
- Custom hooks for date manipulation
- Vue 3 Composition API support
- TypeScript support
- Vue event handling
- v-model support
- Custom directives for date formatting
- Angular Ivy and Angular Signals support
- TypeScript support
- Angular event binding
- Reactive Forms and Template-driven Forms integration
- Customization using CSS variables and direct inputs
- Zero configuration required
- Both module-based and standalone component support
The component includes built-in support for mobile devices:
- Touch swipe gestures for month navigation
- Mobile-optimized tooltips
- Responsive design
- Touch-friendly UI elements
- Chrome 67+
- Firefox 63+
- Safari 10.1+
- Edge 79+
-
Component not rendering: Make sure you've imported the component correctly and that the script is loaded before using the component.
-
Events not firing: Check that you're using the correct event name and that the event handler is properly attached.
-
Styling issues: Verify that your CSS variables are correctly defined and that there are no conflicting styles.
-
Date format issues: Ensure that the format string is valid and that the date is in the correct format.
-
Holidays not showing: Check that the
show-holidays
attribute is set totrue
and that theholiday-types
attribute includes the desired holiday types.
For debugging purposes, you can enable verbose logging:
const picker = document.getElementById('my-picker');
picker.setAttribute('debug', 'true');
This will log additional information to the console, which can help identify issues.
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.