@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

npm version npm downloads Bundle Size License: MIT

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.0
  • vue-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 (فارسی) - RTL
  • gregorian - English - LTR
  • hijri - Arabic (العربية) - RTL
  • chinese - 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:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. 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


🌟 Show Your Support

If this package helps you, please give it a ⭐️ on GitHub!


Made with ❤️ for the Vue community

⬆ Back to Top

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
khorshid

Khorshid — one install for the Jalali & Gregorian date picker: headless core, va...

356
dayfold

Headless, accessible, tiny date picker for any framework. Hijri, Persian and eve...

169 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