An easy-to-use date and time picker component built with vanilla JavaScript/TypeScript. Framework-agnostic and works with React, Vue, Angular, Svelte, or any other frontend framework.
npm install @kevinagyeman/easy-picker
import EasyPicker from '@kevinagyeman/easy-picker'
import '@kevinagyeman/easy-picker/style.css'
// Create a date picker
const picker = new EasyPicker({
container: '#date-picker',
format: 'date',
initialDate: new Date(),
onChange: (date) => {
console.log('Selected date:', date)
}
})
import { useEffect, useRef, useState } from 'react'
import EasyPicker from '@kevinagyeman/easy-picker'
import '@kevinagyeman/easy-picker/style.css'
function DatePickerComponent() {
const [date, setDate] = useState(new Date())
const containerRef = useRef<HTMLDivElement>(null)
const pickerRef = useRef<EasyPicker | null>(null)
useEffect(() => {
if (containerRef.current) {
pickerRef.current = new EasyPicker({
container: containerRef.current,
format: 'date',
initialDate: date,
onChange: setDate
})
}
return () => {
pickerRef.current?.destroy()
}
}, [])
// Sync picker when external state changes
useEffect(() => {
pickerRef.current?.update(date)
}, [date])
return (
<div>
<div ref={containerRef}></div>
<button onClick={() => setDate(new Date())}>Reset to Today</button>
</div>
)
}
<template>
<div ref="pickerContainer"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import EasyPicker from '@kevinagyeman/easy-picker'
import '@kevinagyeman/easy-picker/style.css'
const pickerContainer = ref(null)
let picker = null
onMounted(() => {
picker = new EasyPicker({
container: pickerContainer.value,
format: 'date',
initialDate: new Date(),
onChange: (date) => {
console.log('Selected date:', date)
}
})
})
onUnmounted(() => {
picker?.destroy()
})
</script>
import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core'
import EasyPicker from '@kevinagyeman/easy-picker'
import '@kevinagyeman/easy-picker/style.css'
@Component({
selector: 'app-date-picker',
template: '<div #pickerContainer></div>'
})
export class DatePickerComponent implements AfterViewInit, OnDestroy {
@ViewChild('pickerContainer') pickerContainer!: ElementRef
private picker?: EasyPicker
ngAfterViewInit() {
this.picker = new EasyPicker({
container: this.pickerContainer.nativeElement,
format: 'date',
initialDate: new Date(),
onChange: (date) => {
console.log('Selected date:', date)
}
})
}
ngOnDestroy() {
this.picker?.destroy()
}
}
interface EasyPickerOptions {
// Container element or CSS selector
container: HTMLElement | string
// Initial date to display
initialDate?: Date
// Minimum selectable date
minDate?: Date
// Maximum selectable date
maxDate?: Date
// Callback fired when date changes
onChange?: (value: Date | string | number) => void
// Picker format: 'date', 'datetime', or 'time'
format?: 'date' | 'datetime' | 'time'
// Locale for month names (default: 'en-US')
locale?: string
// Custom CSS class for select elements (e.g., Tailwind classes)
selectClassName?: string
// Custom CSS class for wrapper elements
wrapperClassName?: string
// Return format for date values (default: 'date')
// 'date' - JavaScript Date object
// 'iso' - ISO 8601 string (e.g., "2025-03-15T12:00:00.000Z")
// 'timestamp' - Unix timestamp in milliseconds
// 'date-string' - Date-only string (e.g., "2025-03-15")
returnFormat?: 'date' | 'iso' | 'timestamp' | 'date-string'
}
getDate(): Date | string | numberReturns the currently selected date in the format specified by returnFormat.
const currentDate = picker.getDate()
// Returns Date object by default
// Or ISO string, timestamp, or date-string based on returnFormat option
getRawDate(): DateAlways returns the current date as a JavaScript Date object, regardless of returnFormat.
const rawDate = picker.getRawDate()
// Always returns a Date object
setDate(date: Date): voidProgrammatically sets the picker to a specific date.
picker.setDate(new Date(2025, 5, 15))
update(date: Date): voidUpdates the picker's date from external state (e.g., form state). Unlike setDate(), this is designed for syncing with external state and won't trigger onChange.
// Perfect for form integration
const formState = { date: new Date() };
picker.update(formState.date);
Use update() when:
Use setDate() when:
destroy(): voidRemoves the picker from the DOM and cleans up event listeners.
picker.destroy()
Shows month, day, and year columns.
new EasyPicker({
container: '#picker',
format: 'date'
})
Shows month, day, year, hour, and minute columns.
new EasyPicker({
container: '#picker',
format: 'datetime'
})
Shows hour and minute columns only.
new EasyPicker({
container: '#picker',
format: 'time'
})
Control how date values are returned in the onChange callback and getDate() method:
new EasyPicker({
container: '#picker',
format: 'date',
returnFormat: 'date', // default
onChange: (date) => {
console.log(date) // Date object: Mon Mar 15 2025 12:00:00 GMT...
}
})
new EasyPicker({
container: '#picker',
format: 'date',
returnFormat: 'iso',
onChange: (isoString) => {
console.log(isoString) // "2025-03-15T12:00:00.000Z"
// Perfect for APIs and databases
}
})
new EasyPicker({
container: '#picker',
format: 'date',
returnFormat: 'timestamp',
onChange: (timestamp) => {
console.log(timestamp) // 1710504000000
// Number of milliseconds since Unix epoch
}
})
new EasyPicker({
container: '#picker',
format: 'date',
returnFormat: 'date-string',
onChange: (dateString) => {
console.log(dateString) // "2025-03-15"
// Perfect for HTML input type="date" or simple date storage
}
})
Note: When using format: 'date', dates are set to noon (12:00) to prevent timezone-related issues where the date shifts by one day when converted between timezones.
Pass custom classes via the selectClassName option:
// Tailwind CSS
new EasyPicker({
container: '#picker',
format: 'date',
selectClassName: 'px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500',
wrapperClassName: 'mx-2'
})
// Bootstrap
new EasyPicker({
container: '#picker',
format: 'date',
selectClassName: 'form-select',
wrapperClassName: 'mb-3'
})
Override the default styles in your own CSS:
.easy-picker-select {
/* Your custom select styles */
border: 2px solid #0071e3;
border-radius: 12px;
}
.easy-picker-select:focus {
outline: none;
box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.2);
}
# Install dependencies
npm install
# Run dev server with examples
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
@kevinagyeman/easy-picker/style.css)returnFormat option to choose output format (date, iso, timestamp, date-string)getRawDate() method to always get Date objectonChange callbackMIT
Contributions are welcome! Please open an issue or submit a pull request.