Hire me
Pooyan Razian

jalali-js: Persian calendar for JavaScript

jalali-js: Persian calendar for JavaScript
jalali-js: TypeScript-native Jalali calendar toolkit
Published: August 11, 2026

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

jalali-js documentation homepage
Docs at jalali-js.yanovian.com

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 any with a JSDoc sticker. CalendarDate, CalendarDateTime, and ZonedCalendarDateTime are separate tiers, in the spirit of TC39 Temporal.
  • Display vs storage split. The UI can show Jalali while onChange emits a Gregorian ISO string by default. Opt into a Jalali storage shape when you truly need one.
  • Small core. jalali-js has 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 DatePicker when 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.
jalali-js React playground with DatePicker settings and generated code
Playground: tweak locale, system, and theme, then copy the code

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

PackageRole
jalali-jsConversion core, zero runtime deps
@jalali-js/i18nLocales and formatting (en, fa, ps)
@jalali-js/nlpNatural language date parsing
@jalali-js/holidaysOfficial Iran public holidays
@jalali-js/react / @jalali-js/vue / @jalali-js/webBindings and default DatePicker
@jalali-js/ui-react / ui-vue / ui-webRangePicker, 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.

If you liked the article, feel free to share it with your friends, family, or colleagues. You can also follow me on Dev.to or LinkedIn.

Copyright & Disclaimer

  • All content provided on this article is for informational and educational purposes only. The author makes no representations as to the accuracy or completeness of any information on this site or found by following any link on this site.
  • All the content is copyrighted, except the assets and content I have referenced to other people's work, and may not be reproduced on other websites, blogs, or social media. You are not allowed to reproduce, summarize to create derivative work, or use any content from this website under your name. This includes creating a similar article or summary based on AI/GenAI. For educational purposes, you may refer to parts of the content, and only refer, but you must provide a link back to the original article on this website. This is allowed only if your content is less than 10% similar to the original article.
  • While every care has been taken to ensure the accuracy of the content of this website, I make no representation as to the accuracy, correctness, or fitness for any purpose of the site content, nor do I accept any liability for loss or damage (including consequential loss or damage), however, caused, which may be incurred by any person or organization from reliance on or use of information on this site.
  • The contents of this article should not be construed as legal advice.
  • Opinions are my own and not the views of my employer.
  • English is not my mother-tongue language, so even though I try my best to express myself correctly, there might be a chance of miscommunication.
  • Links or references to other websites, including the use of information from 3rd-parties, are provided for the benefit of people who use this website. I am not responsible for the accuracy of the content on the websites that I have put a link to and I do not endorse any of those organizations or their contents.
  • If you have any queries or if you believe any information on this article is inaccurate, or if you think any of the assets used in this article are in violation of copyright, please contact me and let me know.

jalali-js: Persian calendar for JavaScript

jalali-js: Persian calendar for JavaScript
jalali-js: TypeScript-native Jalali calendar toolkit
Published: August 11, 2026

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

jalali-js documentation homepage
Docs at jalali-js.yanovian.com

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 any with a JSDoc sticker. CalendarDate, CalendarDateTime, and ZonedCalendarDateTime are separate tiers, in the spirit of TC39 Temporal.
  • Display vs storage split. The UI can show Jalali while onChange emits a Gregorian ISO string by default. Opt into a Jalali storage shape when you truly need one.
  • Small core. jalali-js has 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 DatePicker when 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.
jalali-js React playground with DatePicker settings and generated code
Playground: tweak locale, system, and theme, then copy the code

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

PackageRole
jalali-jsConversion core, zero runtime deps
@jalali-js/i18nLocales and formatting (en, fa, ps)
@jalali-js/nlpNatural language date parsing
@jalali-js/holidaysOfficial Iran public holidays
@jalali-js/react / @jalali-js/vue / @jalali-js/webBindings and default DatePicker
@jalali-js/ui-react / ui-vue / ui-webRangePicker, 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.

If you liked the article, feel free to share it with your friends, family, or colleagues. You can also follow me on Dev.to or LinkedIn.

Copyright & Disclaimer

  • All content provided on this article is for informational and educational purposes only. The author makes no representations as to the accuracy or completeness of any information on this site or found by following any link on this site.
  • All the content is copyrighted, except the assets and content I have referenced to other people's work, and may not be reproduced on other websites, blogs, or social media. You are not allowed to reproduce, summarize to create derivative work, or use any content from this website under your name. This includes creating a similar article or summary based on AI/GenAI. For educational purposes, you may refer to parts of the content, and only refer, but you must provide a link back to the original article on this website. This is allowed only if your content is less than 10% similar to the original article.
  • While every care has been taken to ensure the accuracy of the content of this website, I make no representation as to the accuracy, correctness, or fitness for any purpose of the site content, nor do I accept any liability for loss or damage (including consequential loss or damage), however, caused, which may be incurred by any person or organization from reliance on or use of information on this site.
  • The contents of this article should not be construed as legal advice.
  • Opinions are my own and not the views of my employer.
  • English is not my mother-tongue language, so even though I try my best to express myself correctly, there might be a chance of miscommunication.
  • Links or references to other websites, including the use of information from 3rd-parties, are provided for the benefit of people who use this website. I am not responsible for the accuracy of the content on the websites that I have put a link to and I do not endorse any of those organizations or their contents.
  • If you have any queries or if you believe any information on this article is inaccurate, or if you think any of the assets used in this article are in violation of copyright, please contact me and let me know.
Copyright © 2026 - pooyan.info