If you ship a product for Iranian users, or anyone who reads Jalali (Persian, Shamsi) dates, you already know the usual options. One package does the math and stops there. Another gives you a picker glued to Moment. A third is React-only, or Vue-only, and forces a Jalali-shaped value into your forms and database. You end up stitching three libraries together and still worrying about leap years.
jalali-js is an open-source attempt to cover that gap without the usual trade-offs. One small TypeScript core does conversion. Thin bindings sit on top for React, Vue, and plain Web Components. Display Jalali. Store Gregorian by default, same idea as a native <input type="date">.
Docs and live demo · Source on GitHub · npm
Who it is for
- Teams that need a Jalali date picker in React, Vue, Nuxt, or Next.js
- Backend or shared code that only wants conversion, with zero UI
- Pages with no framework at all, via Web Components
- Anyone tired of Moment-based Persian pickers on new projects
What you get
- TypeScript-native types, not
anywith a JSDoc sticker.CalendarDate,CalendarDateTime, andZonedCalendarDateTimeare separate tiers, in the spirit of TC39 Temporal. - Display vs storage split. The UI can show Jalali while
onChangeemits a Gregorian ISO string by default. Opt into a Jalali storage shape when you truly need one. - Small core.
jalali-jshas zero runtime dependencies and stays under a 6 kB budget (minified, brotli), checked in CI. - React, Vue, and Web Components, including SSR-safe timezone handling for Next and Nuxt.
- English, Farsi, and Pashto, plus natural language parsing (
"next Farvardin","فردا","نن"). - Iran holidays, offline, via
@jalali-js/holidays. - Headless first, with a ready
DatePickerwhen you want zero setup. Range picker, inline calendar, and event calendar live in the UI packages. - Validated arithmetic. Leap years are checked against Node's ICU Persian calendar across a multi-thousand-year range, plus an independent reference table.
Install
npm install jalali-js # core
npm install @jalali-js/react # React
npm install @jalali-js/vue # Vue
npm install @jalali-js/web # Web Components, no framework
Quick examples
Core conversion:
import { createCalendar, toGregorian, fromGregorian } from 'jalali-js';
const jalali = createCalendar({ system: 'jalali' });
jalali.today(); // { year: 1403, month: 5, day: 15 }
toGregorian({ year: 1403, month: 5, day: 15 }, 'jalali');
// { year: 2024, month: 8, day: 5 }
fromGregorian({ year: 2024, month: 8, day: 5 }, 'jalali');
// { year: 1403, month: 5, day: 15 }
React picker (Jalali on screen, Gregorian value out):
import '@jalali-js/react/date-picker.css';
import { DatePicker } from '@jalali-js/react';
<DatePicker
system="jalali"
locale="fa"
onChange={(value) => {
// default: Gregorian ISO, e.g. '2024-08-05'
}}
/>;
Vue:
<script setup lang="ts">
import '@jalali-js/vue/date-picker.css';
import { DatePicker } from '@jalali-js/vue';
import type { StorageValue } from 'jalali-js';
import { ref } from 'vue';
const stored = ref<StorageValue>();
</script>
<template>
<DatePicker v-model="stored" system="jalali" locale="fa" />
</template>
No framework:
<jalali-date-picker id="birth-date" system="jalali" locale="fa"></jalali-date-picker>
<script type="module">
import '@jalali-js/web/date-picker.css';
import '@jalali-js/web';
document.getElementById('birth-date').addEventListener('change', (event) => {
console.log(event.detail.value); // Gregorian ISO by default
});
</script>
Packages
| Package | Role |
|---|---|
jalali-js | Conversion core, zero runtime deps |
@jalali-js/i18n | Locales and formatting (en, fa, ps) |
@jalali-js/nlp | Natural language date parsing |
@jalali-js/holidays | Official Iran public holidays |
@jalali-js/react / @jalali-js/vue / @jalali-js/web | Bindings and default DatePicker |
@jalali-js/ui-react / ui-vue / ui-web | RangePicker, EventCalendar, themes |
Why not the older options?
Moment-based Jalali plugins still show up in search results. Moment's own team calls it legacy. Math-only packages leave you to build every picker yourself. Framework pickers often couple the display calendar to the stored value, so a Persian UI quietly writes Persian numbers into your API.
jalali-js keeps layers separate on purpose: core math, framework bindings, then optional UI. Use only what you need. Compare details in the comparison guide.
Try it
Start with the getting started guide, or open the React playground and copy a snippet. MIT licensed, free to use.
Help is welcome. If you give it a try, feedback is appreciated. Bugs and ideas are best as issues, and PRs are welcome too.

