@mahlaparvaz/vue-datepicker
Vue 3 datepicker supporting Jalali, Hijri, Gregorian, Chinese calendars with range, time picker, i18n, RTL, and full customization.
4,158
3
| Install | |
|---|---|
npm install @mahlaparvaz/vue-datepicker |
|
| Latest Version: | 0.5.1 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Dec 16, 2025 |
| Links: | GitHub · npm |
Maintainer: mahlaparvaz
@mahlaparvaz/vue-datepicker
A powerful, lightweight Vue 3 datepicker with multi-calendar support
Features • Installation • Quick Start • Documentation • Examples
🎯 Why Choose This Datepicker?
- 🌍 Multi-Calendar Support: Jalali (Persian), Gregorian, Hijri (Islamic), and Chinese calendars out of the box
- 🎨 Headless Architecture: Complete UI control with scoped slots - build your own design
- 📦 Lightweight: Only ~18KB gzipped after peer dependency optimization
- 🔧 Fully Customizable: 70+ CSS variables, theme props, and custom fonts per calendar
- ♿ Accessible: WCAG compliant with keyboard navigation and ARIA labels
- 🌐 i18n Ready: Built-in internationalization with RTL/LTR support
- ⚡ Zero Config: Automatic CSS injection, no manual imports needed
- 📱 Responsive: Mobile-optimized with touch support
✨ Features
Selection Modes
- ✅ Single Date: Pick one date
- ✅ Range Selection: Start and end dates with visual indicators
- ✅ Multiple Dates: Select multiple non-consecutive dates
Calendar Systems
- 🗓️ Jalali (Persian/Shamsi): Full support for Persian calendar
- 🗓️ Gregorian: Standard international calendar
- 🗓️ Hijri (Islamic): Lunar Islamic calendar
- 🗓️ Chinese: Traditional Chinese calendar
Advanced Features
- ⏰ Time Picker: Optional 12/24-hour time selection
- 🎨 Theming: CSS variables + theme prop with dark mode support
- 🔤 Custom Fonts: Configure fonts per calendar type
- 📅 Date Constraints: Min/max dates, year range limits
- 🔄 Output Formats: Object, timestamp, unix, ISO, custom string, or function
- 💾 Locale Persistence: Remembers user's calendar preference
- ⌨️ Keyboard Navigation: Full keyboard support
- 📱 Mobile Friendly: Responsive overlay with touch gestures
- ♿ High Contrast: Accessibility features built-in
📦 Installation
npm install @mahlaparvaz/vue-datepicker vue-i18n @vueuse/core
yarn add @mahlaparvaz/vue-datepicker vue-i18n @vueuse/core
pnpm add @mahlaparvaz/vue-datepicker vue-i18n @vueuse/core
Peer Dependencies
This package requires:
vue^3.5.0vue-i18n^10.0.0 || ^11.0.0 || ^12.0.0-alpha.3@vueuse/core^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0
🚀 Quick Start
Basic Usage
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const selectedDate = ref(null);
</script>
<template>
<DatepickerHeadless v-model="selectedDate">
<template #default="{ open, formattedDate }">
<input :value="formattedDate" @click="open" placeholder="Select date" readonly />
</template>
</DatepickerHeadless>
</template>
Range Selection
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const dateRange = ref({ start: null, end: null });
</script>
<template>
<DatepickerHeadless v-model="dateRange" mode="range">
<template #default="{ open, formattedDate }">
<input :value="formattedDate" @click="open" placeholder="Select date range" readonly />
</template>
</DatepickerHeadless>
</template>
With Time Picker
<DatepickerHeadless v-model="dateTime" :enable-time="true" :time-format="24">
<template #default="{ open, formattedDate }">
<input
:value="formattedDate"
@click="open"
placeholder="Select date and time"
readonly
/>
</template>
</DatepickerHeadless>
Custom Available Locales
<DatepickerHeadless v-model="date" :available-locales="['jalali', 'gregorian']">
<template #default="{ open, formattedDate }">
<input
:value="formattedDate"
@click="open"
placeholder="Select date (Jalali/Gregorian only)"
readonly
/>
</template>
</DatepickerHeadless>
📖 Documentation
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue |
Object | Array | null |
null |
Selected date(s) - use with v-model |
mode |
'single' | 'range' | 'multiple' |
'single' |
Selection mode |
locale |
String |
User's saved locale | Calendar locale: 'jalali', 'gregorian', 'hijri', 'chinese' |
availableLocales |
Array<String> |
['jalali', 'gregorian', 'hijri', 'chinese'] |
Available calendar types in locale selector |
placeholder |
String |
Auto-generated | Input placeholder text |
format |
String |
'YYYY/MM/DD' |
Display format for dates |
outputFormat |
String | Function |
'object' |
Output format: 'object', 'timestamp', 'unix', 'iso', 'string', or custom function |
outputStringFormat |
String |
'YYYY/MM/DD' |
String format when outputFormat="string" |
enableTime |
Boolean |
false |
Enable time selection |
timeFormat |
Number | String |
24 |
Time format: 12 or 24 |
yearsBefore |
Number |
50 |
Years to show before current year |
yearsAfter |
Number |
50 |
Years to show after current year |
minDate |
Date | String | Object |
null |
Minimum selectable date |
maxDate |
Date | String | Object |
null |
Maximum selectable date |
disabled |
Boolean |
false |
Disable the datepicker |
fontConfig |
Object |
null |
Custom fonts per calendar: { jalali: 'Vazir', gregorian: 'Roboto' } |
theme |
Object |
null |
Theme configuration object |
closeOnSelect |
Boolean |
true |
Close picker after selection (single mode only) |
autoApply |
Boolean |
false |
Auto-apply selection without confirm button |
🎨 Customization
Theme Prop
<DatepickerHeadless
:theme="{
colors: {
primary: '#e91e63',
primaryHover: '#c2185b',
textPrimary: '#ffffff',
background: '#1a1a1a',
},
dimensions: {
inputHeight: '48px',
borderRadius: '12px',
},
spacing: {
padding: '16px',
},
}"
>
<!-- ... -->
</DatepickerHeadless>
CSS Variables
Override globally in your CSS:
:root {
--datepicker-primary-500: #3b82f6;
--datepicker-primary-600: #2563eb;
--datepicker-gray-50: #f9fafb;
--datepicker-gray-900: #111827;
--datepicker-border-radius: 8px;
--datepicker-font-size-base: 14px;
/* ...70+ more variables available */
}
Custom Fonts
<DatepickerHeadless
:font-config="{
jalali: 'Vazir, sans-serif',
gregorian: 'Roboto, sans-serif',
hijri: 'Noto Naskh Arabic, serif',
chinese: 'Noto Sans SC, sans-serif',
}"
>
<!-- ... -->
</DatepickerHeadless>
Load fonts via CDN or npm:
<!-- CDN Example -->
<link
href="https://fonts.googleapis.com/css2?family=Vazir&family=Roboto&display=swap"
rel="stylesheet"
/>
💡 Examples
Multiple Dates Selection
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const selectedDates = ref([]);
</script>
<template>
<DatepickerHeadless v-model="selectedDates" mode="multiple">
<template #default="{ open, formattedDate }">
<button @click="open">
{{ formattedDate || 'Select multiple dates' }}
</button>
</template>
</DatepickerHeadless>
</template>
Persian Calendar with Custom Theme
<DatepickerHeadless
locale="jalali"
:font-config="{ jalali: 'Vazir' }"
:theme="{
colors: {
primary: '#059669',
primaryHover: '#047857',
},
}"
v-model="persianDate"
>
<template #default="{ open, formattedDate, fontFamily }">
<input
:value="formattedDate"
:style="{ fontFamily }"
@click="open"
placeholder="تاریخ را انتخاب کنید"
dir="rtl"
readonly
/>
</template>
</DatepickerHeadless>
Date Range with Time and Constraints
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const bookingDates = ref({ start: null, end: null });
const today = new Date();
const maxDate = new Date();
maxDate.setMonth(maxDate.getMonth() + 6);
</script>
<template>
<DatepickerHeadless
v-model="bookingDates"
mode="range"
:enable-time="true"
:min-date="today"
:max-date="maxDate"
output-format="iso"
>
<template #default="{ open, formattedDate }">
<div class="booking-input" @click="open">
<span>{{ formattedDate || 'Select booking period' }}</span>
</div>
</template>
</DatepickerHeadless>
</template>
Custom Output Format
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const date = ref(null);
// Custom formatter function
const customFormat = (dateObj) => {
if (!dateObj) return null;
return {
year: dateObj.jy || dateObj.year,
month: dateObj.jm || dateObj.month,
day: dateObj.jd || dateObj.day,
formatted: `${dateObj.jy || dateObj.year}-${dateObj.jm || dateObj.month}-${dateObj.jd || dateObj.day}`,
timestamp: Date.now(),
};
};
</script>
<template>
<DatepickerHeadless v-model="date" :output-format="customFormat">
<!-- ... -->
</DatepickerHeadless>
</template>
Programmatic Control
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const date = ref(null);
const setToday = () => {
date.value = { year: 2024, month: 12, day: 16 };
};
const clearDate = () => {
date.value = null;
};
</script>
<template>
<div>
<DatepickerHeadless v-model="date">
<template #default="{ open, formattedDate, close }">
<input :value="formattedDate" @click="open" readonly />
</template>
</DatepickerHeadless>
<button @click="setToday">Set Today</button>
<button @click="clearDate">Clear</button>
</div>
</template>
🌐 Internationalization
Available Locales
jalali- Persian/Farsi (فارسی) - RTLgregorian- English - LTRhijri- Arabic (العربية) - RTLchinese- Chinese (中文) - LTR
Dynamic Locale Switching
<script setup>
import { ref } from 'vue';
import { DatepickerHeadless } from '@mahlaparvaz/vue-datepicker';
const date = ref(null);
const currentLocale = ref('jalali');
</script>
<template>
<DatepickerHeadless v-model="date" v-model:locale="currentLocale">
<template #default="{ open, formattedDate }">
<input :value="formattedDate" @click="open" readonly />
</template>
</DatepickerHeadless>
<!-- Locale persists to localStorage automatically -->
</template>
🔧 Utility Functions
Export and use validation utilities:
import {
isValidJalaaliDate,
isValidGregorianDate,
isValidDate,
parseDate,
} from '@mahlaparvaz/vue-datepicker';
// Validate Jalali date
isValidJalaaliDate(1403, 9, 15); // true
// Validate Gregorian date
isValidGregorianDate(2024, 2, 29); // true (leap year)
// Parse date strings
const parsed = parseDate('1403/09/15');
// { jy: 1403, jm: 9, jd: 15 }
// Universal date validation
isValidDate({ year: 2024, month: 12, day: 16 }); // true
🤝 Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
Development Setup
# Install dependencies
npm install
# Start development server
npm run dev
# Build library
npm run build
# Lint code
npm run lint
# Format code
npm run format
📝 Changelog
See CHANGELOG.md for detailed release notes.
📄 License
MIT © Mahla Zohourparvaz
💬 Support
- 📧 Email: mahla.zph@gmail.com
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
🌟 Show Your Support
If this package helps you, please give it a ⭐️ on GitHub!
Made with ❤️ for the Vue community
Related Packages
vue-jalali-datepicker
A lightweight, zero-dependency Persian (Jalali / Shamsi) date and range picker f...
539
0
vue-persian-calendar-datepicker
An accessible Vue 3 Persian (Jalali) calendar, date picker, and time picker with...
3,651
0
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.5.1 | ^3.5.0 | MIT | |
| 0.5.0 | ^3.5.0 | MIT | |
| 0.4.6 | ^3.5.0 | MIT | |
| 0.4.3 | ^3.5.0 | MIT | |
| 0.4.2 | ^3.5.0 | MIT | |
| 0.4.1 | ^3.5.0 | MIT | |
| 0.4.0 | ^3.5.0 | MIT | |
| 0.3.2 | ^3.5.0 | MIT | |
| 0.3.1 | ^3.5.0 | MIT | |
| 0.3.0 | ^3.5.0 | MIT | |
| 0.2.13 | ^3.5.0 | MIT | |
| 0.2.12 | ^3.5.0 | MIT | |
| 0.2.11 | ^3.5.0 | MIT | |
| 0.2.10 | ^3.5.0 | MIT | |
| 0.2.8 | ^3.5.0 | MIT | |
| 0.2.7 | ^3.5.0 | MIT | |
| 0.2.6 | ^3.5.0 | MIT | |
| 0.2.5 | ^3.5.0 | MIT | |
| 0.2.4 | ^3.5.0 | MIT | |
| 0.2.3 | ^3.5.0 | MIT | |
| 0.2.2 | ^3.5.0 | MIT | |
| 0.2.1 | ^3.5.0 | MIT | |
| 0.2.0 | ^3.5.0 | MIT | |
| 0.1.4 | ^3.5.0 | MIT | |
| 0.1.3 | ^3.5.0 | MIT | |
| 0.1.2 | ^3.5.0 | MIT | |
| 0.1.1 | ^3.5.0 | MIT | |
| 0.1.0 | ^3.5.0 | MIT |