# JalaliDatePicker gives web forms a Jalali calendar picker

> JalaliDatePicker is a small TypeScript written datepicker for the Jalali calendar that has no runtime dependencies and is driven by a global object and a handful of data attributes on the input. It handles dates, times, ranges, multiple selection and per input configuration, and the npm package is published at version 1.0.0 with no tagged GitHub releases.

**majidh1/JalaliDatePicker** — A lightweight and simple jalali datepicker. powerful javascript datepicker with no dependencies

- Repository: https://github.com/majidh1/JalaliDatePicker
- Website: https://majidh1.github.io/JalaliDatePicker/
- Stars: 663 · Forks: 90
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/majidh1-jalalidatepicker

## A global object and a data attribute, nothing else

The design of JalaliDatePicker is deliberately old school, and understanding that is the fastest way to decide whether it fits.

There is no framework component and no module import in the documented usage. You mark an input with a data attribute, load the script, and start a watcher:

```html
<input data-jdp>
```

```html
<script>
 jalaliDatepicker.startWatch();
</script>
```

After that, every input matching the default selector input[data-jdp] opens the picker when it receives focus. The script creates one global object named jalaliDatepicker, and its public surface is four methods:

```js
jalaliDatepicker.startWatch(options);
jalaliDatepicker.show(input);
jalaliDatepicker.hide();
jalaliDatepicker.updateOptions(options);
```

startWatch attaches the picker to the inputs matching the selector, show opens it manually for a specific HTMLInputElement, hide closes the current one, and updateOptions changes the settings after the watcher has started.

For a team shipping a server rendered page or a static marketing site with one date field, that is enough and it stays out of the dependency tree. For a team running a component based front end, the global object is the thing that has to be worked around, because there is no component to wrap and no props to pass.

## Three ways to get the files onto the page

The installation section covers the three routes you would expect, and the readme gives the exact tags for each.

The npm route installs the package:

```bash
npm i @majidh1/jalalidatepicker
```

and then the built CSS and JS are added to the page:

```html
<link rel="stylesheet" href="jalalidatepicker.min.css">
<script src="jalalidatepicker.min.js"></script>
```

The CDN route points the same two tags at unpkg:

```html
<link rel="stylesheet" href="https://unpkg.com/@majidh1/jalalidatepicker/dist/jalalidatepicker.min.css">
<script src="https://unpkg.com/@majidh1/jalalidatepicker/dist/jalalidatepicker.min.js"></script>
```

The third route is to copy the prepared files out of the dist folder of the package yourself, which is what the readme calls manual use of dist.

The package metadata supports this. The name is @majidh1/jalalidatepicker, the main entry is dist/jalalidatepicker.min.js, the licence is MIT and the publish config points at the npmjs registry, so all three routes resolve to the same artifact. The published version recorded in package.json is 1.0.0, which is worth noting for a library that is only at its first version.

## Options decide whether a picker shows a date, a time or both

The behaviour is driven by one options object passed to startWatch, and the readme publishes the defaults for each key, which is unusually helpful.

The date key defaults to true and turns the calendar on. The time key defaults to false, so a plain picker is date only. The hasSecond key defaults to true and controls the seconds dropdown in time mode, and it accepts the special value attr, meaning the value is read per input from data-jdp-has-second rather than globally. The initDate default is today's date or the value already in the input, and initTime defaults to the current system time.

The limits are where the design gets more interesting. minDate and maxDate default to undefined and each accepts an object, the literal string today, or the string attr. The same trio applies to minTime and maxTime, except those accept an object or attr. The attr mode reads the bound from an attribute on each input, so two inputs on the same page can have different limits:

```html
<script>
 jalaliDatepicker.startWatch({
  minDate: {
   year: 1403,
   month: 1,
   day: 10
  },
  maxDate: {
   year: 1403,
   month: 12,
   day: 29
  }
 });
</script>
```

The rest of the defaults are about placement and behaviour rather than the calendar itself. The selector is input[data-jdp], the container is body, the zIndex is 1000, autoShow and autoHide are both true, autoReadOnlyInput depends on whether the browser is on mobile, and hideAfterChange closes the picker after a change while hideAfterChangeWithTime stays false so a time picker stays open.

## Range and multiple selection, chosen per input or globally

Three selection modes are supported: single, range and multiple. The mode can be set globally when startWatch is called, or per input by setting the mode option to attr and giving each input its own data-jdp-mode attribute with one of the values single, range or multiple.

A range picker writes the two chosen dates joined by a separator, and the separator is configurable:

```js
jalaliDatepicker.startWatch({
  mode: "range",
  rangeSeparator: " - "
});
```

A multiple picker writes a list of dates, sorted, joined by its own separator:

```js
jalaliDatepicker.startWatch({
  mode: "multiple",
  multipleSeparator: ", "
});
```

The readme states one detail that matters for form handling: in range and multiple modes the output is written as date only, without a time component. If the same field sometimes needs a time and sometimes does not, the per input mode attribute is the mechanism for that.

The output format itself is a Jalali date string with slash separators in the form 1403/01/01, and the readme shows the range and multiple results in exactly that shape, for example 1403/01/01 - 1403/01/05 and 1403/01/01, 1403/01/05.

## dayRendering is where the calendar becomes your business calendar

The most capable hook is the dayRendering callback, which receives the options for a single day and the input it belongs to, and returns a modified day. It can disable a day, add a class, or mark the day as a holiday:

```js
jalaliDatepicker.startWatch({
 dayRendering(dayOptions, input) {
  if (dayOptions.weekDay === 6) {
   return {
    ...dayOptions,
    isValid: false
   };
  }

  return {
   isHoliday: dayOptions.month === 1 && dayOptions.day <= 4,
   className: dayOptions.month === 1 && dayOptions.day <= 4 ? "nowruz" : "",
   isValid: dayOptions.isValid
  };
 }
});
```

Two things to get right. The weekDay value is available inside dayOptions, and in the default ordering of Jalali days Saturday is 0 and Friday is 6, so a Friday holiday is the value 6 rather than the value 5 you might expect from a Monday first ordering. The second is that a callback which returns a fresh object with only three keys replaces the day options rather than merging them, which is why the isValid field is carried through explicitly in the second branch of the example.

The example also shows the intended use, marking the first four days of month 1 as a holiday and giving them a class so the stylesheet can highlight them.

## A second input can receive the Gregorian value

The library can write the selected date into a different input in Gregorian form, which is how a form can show a Jalali picker while storing a standard date.

The two options are targetValueInput, a selector for the input to write to, and targetValueType, which is set to gregorian:

```js
jalaliDatepicker.startWatch({
  targetValueInput: "#gregorian-date",
  targetValueType: "gregorian"
});
```

The readme gives the worked example, where picking 1403/01/01 in the picker writes 2024-03-20 into the target field. So the conversion happens in the library rather than in application code.

The practical note is that this is a one way display convenience, not a full i18n date layer. The readme documents the target input and the Gregorian value it receives, and does not describe a reverse direction, a locale setting or a way to display the Gregorian date inside the picker itself.

## TypeScript source, Vite builds and an ES5 conversion step

The build setup is visible in package.json and it explains a detail in the installation instructions.

The source is TypeScript and there are two build modes. build:unminified runs tsc followed by vite build with the unminified mode, and build:minified does the same with the minified mode. Then convert-dist-es5 runs Babel over the built file and then Terser, which is the step that produces the ES5 compatible minified file that the readme tells you to include with a script tag.

That chain matters for browser support, since an ES5 output is what a page served to older browsers needs, and it explains why the dist folder carries both a jalalidatepicker.min.css and a jalalidatepicker.min.js. The prepublishOnly script runs the full build, so the published package is always the Babel and Terser processed artifact.

The rest of the tooling is standard. Linting runs eslint over the TypeScript sources, tests run with vitest, and there is a vitest.config.ts alongside a test/ directory. The development server uses vite with a separate dev configuration file, and a preview script serves the built output.

The repository also carries the housekeeping a maintained project tends to have, with ChangeLog.md and an English ChangeLog-en.md, an English README alongside the Persian one, a Sample.md, a SECURITY.md file, a code of conduct and a contributing guide.

## MIT licensed, frequently pushed, but not versioned in git

The licence is MIT, stated in the readme badge and in the LICENSE file at the top of the repository, so the code can be reused with attribution and no copyleft obligation on your own product.

The activity is current. The last push was on 2026-10-18 and the repository is not archived, and the project publishes a demo page at majidh1.github.io/JalaliDatePicker. The repository also carries a file size badge set in the res folder, which is a reminder of the project's stated goal of being small.

What is missing is release tagging. There are no GitHub releases, so the only version marker is the npm version field, which reads 1.0.0. For a front end dependency that is usually fine, because the version is locked in the lock file, but it means there is no published changelog entry attached to a tag and no way to pull a specific build from the releases page.

The npm package is the distribution channel, and the maintainer is a single named author in the package metadata. The Persian first line of the readme describes it as a lightweight datepicker with no dependencies for selecting a Jalali date, a time, or a date and time on web pages, which is an accurate summary of what the rest of the documentation shows.

## Conclusion

Adopt JalaliDatePicker when a form on a Persian or Iranian site needs a Jalali calendar input and your build already loads a plain script tag, since it needs no framework and no dependency tree. Skip it if your application is a modern component based front end, because the library exposes a single global object rather than a component API, and if you need a formal release trail, since the npm package sits at version 1.0.0 with no GitHub releases behind it. Before shipping, check the ChangeLog-en.md file, confirm that the day numbering you rely on matches the library's convention with Saturday as zero, and verify the value written into your input in both Jalali and the Gregorian target field.

## FAQ

### How do I install JalaliDatePicker?

Run npm i @majidh1/jalalidatepicker and add the two tags for jalalidatepicker.min.css and jalalidatepicker.min.js to the page, or point those tags at unpkg for a CDN version. The built files can also be copied directly from the dist folder of the package.

### How is the JalaliDatePicker attached to an input?

Add the data-jdp attribute to the input and call jalaliDatepicker.startWatch() after the script loads. Every input matching the default selector input[data-jdp] then opens the picker on focus, and the selector can be changed through the selector option.

### Can JalaliDatePicker show a time picker or a date and time picker?

Yes. The time option defaults to false and turns time selection on, and hasSecond controls the seconds dropdown, with the special value attr reading data-jdp-has-second from each input separately.

### How do I set minimum and maximum dates?

The minDate and maxDate options accept an object with year, month and day, the literal today, or the value attr to read the bound from data-jdp-min-date and data-jdp-max-date on each input. The readme shows limits running from 1403/01/10 to 1403/12/29.

### What is the difference between range and multiple mode?

Range mode writes the two chosen dates joined by rangeSeparator, for example 1403/01/01 - 1403/01/05, while multiple mode writes a sorted list joined by multipleSeparator, for example 1403/01/01, 1403/01/05. Both modes write the date only, without a time.

### How do I disable specific days in the Jalali calendar?

Use the dayRendering callback, which receives the day options and the input, and return isValid set to false for a day that should not be selectable. The readme notes that weekDay is exposed on dayOptions, with Saturday as 0 and Friday as 6 in the default Jalali ordering.

## Sources

- [Issues](https://github.com/majidh1/JalaliDatePicker/issues)
- [License: MIT](https://github.com/majidh1/JalaliDatePicker/blob/main/LICENSE)
- [majidh1/JalaliDatePicker on GitHub](https://github.com/majidh1/JalaliDatePicker)
- [Project website](https://majidh1.github.io/JalaliDatePicker/)
- [README](https://github.com/majidh1/JalaliDatePicker/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/majidh1-jalalidatepicker
