Vanilla JS Date Picker with Range Selection – EssealDatePicker

Category: Date & Time , Javascript | February 12, 2026
Authoresseal-dev
Last UpdateFebruary 12, 2026
LicenseMIT
Views48 views
Vanilla JS Date Picker with Range Selection – EssealDatePicker

EssealDatePicker is a lightweight framework-agnostic JavaScript date picker library that supports single date selection, date ranges, and localization.

You can attach the date picker to any text input and use it natively in React, Vue, Angular, and plain HTML environments.

Features:

  • Range Selection Mode: Switch between single-date and date-range picking with one configuration option.
  • Custom Theming: Accepts hex color codes for primary and text colors.
  • Date Restrictions: Set minimum and maximum selectable dates.
  • Keyboard Accessible: Includes ARIA labels and keyboard navigation support for screen readers.
  • Locale Support: Automatically detects browser locale.
  • Custom Formatters: Replace default date formatting with your own function.

How To Use It:

1. Import the EssealDatePicker into your document.

import EssealDatePicker from "./index.js";

2. Attach the date picker to a standard input field.

<input id="example" type="text" placeholder="Select a date" readonly />
const picker = new EssealDatePicker("#example", {
  // options here
});

3. Configuration options.

  • mode (string): Sets selection behavior. Accepts 'single' for one date or 'range' for start/end selection. Default is 'single'.
  • locale (string): Defines language for month names and date formatting. Uses browser default if not specified. Examples: 'en-US', 'fr-FR', 'ja-JP'.
  • minDate (Date | string | null): Blocks selection of dates before this value. Users cannot click disabled dates. Pass a Date object or ISO string. Default is null (no minimum).
  • maxDate (Date | string | null): Blocks selection of dates after this value. Prevents future date selection when needed. Pass a Date object or ISO string. Default is null (no maximum).
  • primaryColor (string): Sets the highlight color for selected dates. Must be hexadecimal format (#3b82f6 or #f00). RGB and HSL formats will not work. Default is '#3b82f6'.
  • textColor (string): Controls text color throughout the calendar interface. Must be hex format. Default is '#1f2937'.
  • zIndex (number): Positions the calendar popup in the stacking context. Increase this value if other elements cover the calendar. Default is 9999.
  • format (function): Customizes how dates display in the input field. Receives a Date object and returns a string. Default formats as YYYY-MM-DD (date.toLocaleDateString('en-CA')).
  • onChange (function | null): Callback that fires when user selects a date. Receives the selected Date object (single mode) or an object with start and end properties (range mode). Default is null.
const picker = new EssealDatePicker("#example", {
  mode: 'single',
  locale: navigator.language || 'en-US',
  minDate: null,
  maxDate: null,
  primaryColor: '#3b82f6',
  textColor: '#1f2937',
  zIndex: 9999,
  format: (date) => date.toLocaleDateString('en-CA'),
  onChange: null,
});

4. API methods.

// Opens the calendar popup programmatically
// Useful for custom trigger buttons
picker.open();
// Closes the calendar popup
// Call this to hide the picker without selecting a date
picker.close();
// Removes all event listeners and DOM elements
// CRITICAL: Always call this before removing the picker
// Prevents memory leaks in React, Vue, and Angular
picker.destroy();

React Integration:

import { useEffect, useRef } from "react";
import EssealDatePicker from "esseal-date-picker";
function DatePickerComponent() {
  const inputRef = useRef(null);
  const pickerRef = useRef(null);
  useEffect(() => {
    // Initialize the date picker after component mounts
    pickerRef.current = new EssealDatePicker(inputRef.current, {
      primaryColor: "#3b82f6",
      onChange: (date) => {
        console.log("Selected:", date);
        // The input value updates automatically
        // React state will sync on next render
      },
    });
    // Critical: destroy() prevents memory leaks
    return () => {
      if (pickerRef.current) {
        pickerRef.current.destroy();
      }
    };
  }, []); // Empty dependency array = run once on mount
  return (
    <div>
      <label htmlFor="date-picker">Select Date:</label>
      {/* readOnly prevents manual text entry */}
      <input
        ref={inputRef}
        type="text"
        id="date-picker"
        placeholder="Click to select date"
        readOnly
      />
    </div>
  );
}
export default DatePickerComponent;

Vue 3 Integration

<template>
  <div>
    <label for="date-picker">Select Date:</label>
    <!-- ref creates a reference to this DOM element -->
    <input
      ref="dateInput"
      type="text"
      id="date-picker"
      placeholder="Click to select date"
      readonly
    />
  </div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import EssealDatePicker from "esseal-date-picker";
const dateInput = ref(null);
let picker = null;
onMounted(() => {
  // Access the native DOM element with .value
  picker = new EssealDatePicker(dateInput.value, {
    onChange: (date) => {
      console.log("Selected:", date);
    },
  });
});
// Clean up when component unmounts
onUnmounted(() => {
  if (picker) {
    picker.destroy();
  }
});
</script>

Angular Integration

import {
  Component,
  ElementRef,
  ViewChild,
  OnInit,
  OnDestroy,
} from "@angular/core";
import EssealDatePicker from "esseal-date-picker";
@Component({
  selector: "app-date-picker",
  template: `
    <div>
      <label for="date-picker">Select Date:</label>
      <!-- #dateInput creates a template reference -->
      <input
        #dateInput
        type="text"
        id="date-picker"
        placeholder="Click to select date"
        readonly
      />
    </div>
  `,
})
export class DatePickerComponent implements OnInit, OnDestroy {
  @ViewChild("dateInput", { static: true }) dateInput!: ElementRef;
  private picker: any;
  ngOnInit() {
    // Access native element through ElementRef
    this.picker = new EssealDatePicker(this.dateInput.nativeElement, {
      onChange: (date: Date) => {
        console.log("Selected:", date);
      },
    });
  }
  // Angular calls this before destroying component
  ngOnDestroy() {
    if (this.picker) {
      this.picker.destroy();
    }
  }
}

FAQs:

Q: Can I style the calendar beyond just changing colors?
A: The picker injects CSS with the class prefix dp-. You can add your own stylesheet that targets these classes. Override properties like border-radius, font-family, or box-shadow.

Q: How do I get the selected date value for form submission?
A: The picker updates the input’s value attribute automatically. Standard form submissions include this value. Access it with formData.get('inputName') or input.value in JavaScript. The format depends on your format option.

Q: Why do I get a “Target input not found” error?
A: The picker runs before the DOM element exists. This happens when you pass a CSS selector but the element hasn’t rendered yet. Move initialization after the element appears. In frameworks, use lifecycle hooks (useEffect, onMounted, ngOnInit) to delay initialization.

You Might Be Interested In:


Leave a Reply