npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pardis-jalali-datepicker

v1.0.2

Published

A modern, zero-dependency Persian (Jalali/Shamsi) datepicker — multi-instance, inline mode, range selection, input masking, and three built-in themes.

Readme

Pardis Jalali Datepicker

A modern, zero-dependency Persian (Jalali/Shamsi) datepicker built with a headless architecture. Supports multiple independent instances, inline mode, range selection, input masking, and three built-in themes.


Screenshots

| Popover — Single Date | Popover — Range Selection | |---|---| | Modern theme, single date picker | Modern theme, range selection |

Inline Mode — Glassmorphism Theme

Inline mode with glass theme showing two side-by-side calendars


Features

  • Zero dependencies — pure vanilla JS, no external libraries
  • Headless architecture — engine, renderer, and input mask are fully decoupled
  • Multi-instance — any number of independent pickers on one page
  • Inline mode — always-visible calendar without an input field
  • Range selection — pick a start and end date with hover preview
  • Input masking — auto-formats Persian digits with slash separators
  • Three themes — Modern, Glassmorphism, Classic/Dark
  • Dual output — returns both Jalali and Gregorian date data simultaneously
  • Precise conversion — correct Jalaali ↔ Gregorian algorithm (integer division, not Math.floor)
  • RTL — fully right-to-left layout

Project Structure

pardis-jalali-datepicker/
├── lib/
│   ├── pardis-jalali-datepicker.js   # Library — classes only
│   └── pardis-jalali-datepicker.css  # Library — CSS variables, themes, component styles
├── demo/
│   ├── demo.js                        # Demo page script
│   └── demo.css                       # Demo page styles
└── index.html                         # Interactive demo page

Quick Start

Include the library files and create a datepicker on any <input>:

<link rel="stylesheet" href="lib/pardis-jalali-datepicker.css">

<input id="myInput" class="pardis-input" type="text" placeholder="۱۴۰۴/۰۱/۰۱">

<script src="lib/pardis-jalali-datepicker.js"></script>
<script>
  const dp = new PardisDatepicker('#myInput', {
    outputFormat: 'both',
    onChange: (payload) => {
      console.log(payload.jalali.formatted);    // '1404/01/01'
      console.log(payload.gregorian.formatted); // '2025-03-21'
    }
  });
</script>

Installation

npm

npm install pardis-jalali-datepicker

Manual

Copy lib/pardis-jalali-datepicker.js and lib/pardis-jalali-datepicker.css into your project and include them directly.

Note: The library uses the Vazirmatn font by default (via CSS variable --pardis-font). Load it yourself (e.g. from Google Fonts) or override the variable with your preferred font.


API Reference

new PardisDatepicker(target, options)

| Option | Type | Default | Description | |---|---|---|---| | inline | boolean | false | Render calendar always-visible inside the target element (no input needed) | | rangeMode | boolean | false | Enable range selection (start + end date) | | outputFormat | 'both' | 'jalali' | 'gregorian' | 'both' | Shape of the payload passed to callbacks | | initialYear | number | current year | Jalali year to display on first render | | initialMonth | number | current month | Jalali month (1–12) to display on first render | | minDate | {jy, jm, jd} | null | Earliest selectable date | | maxDate | {jy, jm, jd} | null | Latest selectable date | | onChange | function | null | Called when a single date is selected. Receives a date payload | | onRangeStart | function | null | Called when the first date of a range is picked. Receives a date payload | | onRangeSelect | function | null | Called when both range dates are selected. Receives { start, end } where each is a date payload | | onClear | function | null | Called when the selection is cleared |


Methods

| Method | Description | |---|---| | dp.open() | Open the popover (no-op in inline mode) | | dp.close() | Close the popover (no-op in inline mode) | | dp.getValue() | Returns the current date payload, or null if nothing is selected | | dp.setValue(jy, jm, jd) | Programmatically select a Jalali date | | dp.clear() | Clear the current selection | | dp.setOption(key, value) | Update an option after construction (currently supports rangeMode and outputFormat only) | | dp.destroy() | Remove all event listeners and DOM elements created by this instance |

Access the underlying engine directly via dp.engine for advanced use.


Date Payload

When outputFormat: 'both' (default), callbacks receive:

{
  jalali: {
    year,             // 1404
    month,            // 1
    day,              // 1
    monthName,        // 'فروردین'
    formatted,        // '1404/01/01'
    formattedPersian, // '۱۴۰۴/۰۱/۰۱'
    timestamp         // Unix ms
  },
  gregorian: {
    year,             // 2025
    month,            // 3
    day,              // 21
    monthName,        // 'March'
    formatted,        // '2025-03-21'
    date,             // native Date object
    timestamp         // Unix ms
  },
  iso,                // '2025-03-21'
  timestamp           // Unix ms
}

When outputFormat: 'jalali', the Jalali fields are returned directly (no nesting).
When outputFormat: 'gregorian', the Gregorian fields are returned directly.


Usage Examples

Popover — Single Date

const dp = new PardisDatepicker('#dateInput', {
  outputFormat: 'both',
  onChange: ({ jalali, gregorian, iso }) => {
    console.log(jalali.formattedPersian); // '۱۴۰۴/۰۱/۰۱'
    console.log(gregorian.formatted);     // '2025-03-21'
    console.log(iso);                     // '2025-03-21'
  },
  onClear: () => console.log('cleared')
});

Popover — Range Selection

const dp = new PardisDatepicker('#rangeInput', {
  rangeMode: true,
  outputFormat: 'both',
  onRangeSelect: ({ start, end }) => {
    console.log(start.jalali.formatted); // '1404/01/05'
    console.log(end.jalali.formatted);   // '1404/01/15'
  }
});

Inline — Always Visible

// target must be a container element, not an input
const dp = new PardisDatepicker('#calendarContainer', {
  inline: true,
  outputFormat: 'both',
  onChange: (payload) => console.log(payload.jalali.formatted)
});

Inline — Range

const dp = new PardisDatepicker('#rangeContainer', {
  inline: true,
  rangeMode: true,
  onRangeSelect: ({ start, end }) => {
    console.log(start.jalali.formatted, '→', end.jalali.formatted);
  }
});

With Min/Max Dates

const dp = new PardisDatepicker('#input', {
  minDate: { jy: 1404, jm: 1, jd: 1 },
  maxDate: { jy: 1404, jm: 6, jd: 31 },
  onChange: (payload) => console.log(payload)
});

Programmatic Control

const dp = new PardisDatepicker('#input');

dp.setValue(1404, 3, 15);   // select 1404/03/15
dp.getValue();               // returns current payload
dp.clear();                  // clear selection
dp.open();                   // open popover
dp.close();                  // close popover
dp.destroy();                // clean up

// Toggle range mode at runtime
dp.setOption('rangeMode', true);

Low-Level Engine Access

dp.engine.goToNextMonth();
dp.engine.goToPrevMonth();
dp.engine.goToNextYear();
dp.engine.goToPrevYear();
dp.engine.goToToday();
dp.engine.setViewMode('month'); // 'day' | 'month' | 'year'
dp.engine.on('viewChange', ({ year, month, monthName, viewMode }) => {
  console.log(monthName, year);
});

Static Helper

// Convert any Jalali date to a full payload without creating a picker
const payload = PardisEngine.buildDatePayload(1404, 1, 1, 'both');
payload.jalali.formatted;    // '1404/01/01'
payload.gregorian.formatted; // '2025-03-21'
payload.iso;                 // '2025-03-21'
payload.timestamp;           // Unix ms

Themes

Apply a theme by setting data-pardis-theme on <html> and a body class:

| Theme | data-pardis-theme | <body> class | |---|---|---| | Modern (default) | (remove attribute) | theme-modern | | Glassmorphism | glass | theme-glass | | Classic / Dark | classic | theme-classic |

// Switch to glass theme
document.documentElement.setAttribute('data-pardis-theme', 'glass');
document.body.className = 'theme-glass';

// Switch back to modern
document.documentElement.removeAttribute('data-pardis-theme');
document.body.className = 'theme-modern';

Input Styling

Add the pardis-input class to your <input> for the built-in styled input:

<div class="pardis-input-wrapper">
  <input class="pardis-input" id="myInput" type="text"
         placeholder="۱۴۰۴/۰۱/۰۱" autocomplete="off">
  <span class="pardis-input-icon">📅</span>
</div>

The input wrapper is created automatically by PardisDatepicker if it does not already exist. You can also wrap it yourself for custom layouts.


Internal Architecture

The library is composed of four independent classes:

| Class | Role | |---|---| | JalaaliUtil | Pure Jalaali ↔ Gregorian math (no DOM, no state) | | PardisEngine | Calendar state machine — selection, navigation, event emitter | | PardisRenderer | Binds engine state to a DOM container, re-renders on change | | PardisInputMask | Handles Persian digit input and auto-slash formatting | | PardisDatepicker | Public API — wires the above together, manages popover/inline lifecycle |

You can use PardisEngine and PardisRenderer directly to build a fully custom UI without using PardisDatepicker.


Browser Support

Works in all modern browsers (Chrome, Firefox, Safari, Edge). No polyfills required.


License

MIT