Create and configure date pickers programmatically for dynamic applications
DateRangePicker class
attached to plain <input> elements — the underlying component, not the
keen_web_daterangepicker LiveView wrapper. It's included for 1:1 parity with
upstream; the wrapper itself is shown on every other page.
While the web component approach (<web-daterangepicker>) is convenient for static configurations, JavaScript instantiation is useful when:
<input type="text"> element first, then pass it to the DateRangePicker constructor. The class will attach the calendar functionality to your existing input.
Unlike the web component approach, the DateRangePicker class does NOT automatically inject styles. You MUST import the CSS separately, or you'll see an unstyled matrix of day numbers.
// When using a bundler (Webpack, Vite, Rollup, etc.)
import { DateRangePicker } from '@keenmate/web-daterangepicker';
import '@keenmate/web-daterangepicker/dist/style.css';
const picker = new DateRangePicker(inputElement, options);
<!-- In your HTML <head> -->
<link rel="stylesheet" href="./node_modules/@keenmate/web-daterangepicker/dist/style.css">
<script type="module">
import { DateRangePicker } from '@keenmate/web-daterangepicker';
const picker = new DateRangePicker(inputElement, options);
</script>
// If you want to customize variables or build from source
import { DateRangePicker } from '@keenmate/web-daterangepicker';
import '@keenmate/web-daterangepicker/src/css/main.css';
const picker = new DateRangePicker(inputElement, options);
// Inject styles programmatically (no CSS import needed!)
import { DateRangePicker } from '@keenmate/web-daterangepicker';
DateRangePicker.injectGlobalStyles();
const picker = new DateRangePicker(inputElement, options);
<web-daterangepicker>) uses Shadow DOM and injects styles automatically into its isolated scope. The DateRangePicker class doesn't use Shadow DOM - it creates calendar elements in the regular DOM, so it expects global CSS to be loaded separately.
Create a simple single-date picker with default options.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
const inputElement = document.getElementById('input-1');
const picker = new DateRangePicker(inputElement, {
selectionMode: 'single',
dateFormatMask: 'YYYY-MM-DD',
onSelect: (date) => {
// Single mode: date is a Date object directly
document.getElementById('output-1').textContent = `Selected: ${inputElement.value}`;
}
});
Create a range picker with 2 visible months and custom configuration.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
const picker = new DateRangePicker(document.getElementById('input-2'), {
selectionMode: 'range',
visibleMonthsCount: 2,
monthLayout: 'horizontal',
dateFormatMask: 'YYYY-MM-DD',
onSelect: (detail) => {
const { start, end } = detail; // range mode: { start, end }
const nights = Math.floor((end - start) / (1000 * 60 * 60 * 24));
document.getElementById('output-2').innerHTML =
`Start: ${start.toLocaleDateString()}<br>End: ${end.toLocaleDateString()}<br>Nights: ${nights}`;
}
});
Configure min/max dates, disabled weekends, and specific disabled dates.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
const today = new Date();
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
const picker = new DateRangePicker(document.getElementById('input-3'), {
selectionMode: 'single',
dateFormatMask: 'YYYY-MM-DD',
minDate: firstDay,
maxDate: lastDay,
disabledWeekdays: [0, 6], // Disable Sunday (0) and Saturday (6)
onSelect: (detail) => {
document.getElementById('output-3').textContent = `Selected business day: ${detail.formattedValue}`;
}
});
Create pickers with various date format masks.
// European format
const pickerEU = new DateRangePicker(document.getElementById('input-4a'), {
selectionMode: 'single',
dateFormatMask: 'DD.MM.YYYY',
onSelect: (detail) => {
document.getElementById('output-4a').textContent = `Selected: ${detail.formattedValue}`;
}
});
// US format
const pickerUS = new DateRangePicker(document.getElementById('input-4b'), {
selectionMode: 'single',
dateFormatMask: 'MM/DD/YYYY',
onSelect: (detail) => {
document.getElementById('output-4b').textContent = `Selected: ${detail.formattedValue}`;
}
});
Create a standalone calendar without an input field.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
// For inline mode, pass null as the input element
const picker = new DateRangePicker(null, {
selectionMode: 'single',
positioningMode: 'inline',
container: document.getElementById('inline-container'),
onSelect: (date) => {
document.getElementById('output-5').textContent = `Selected: ${date.toLocaleDateString()}`;
}
});
positioningMode: 'inline', pass null as the first argument and specify a container in the options.
Display 6 months in a grid layout for easier navigation.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
const picker = new DateRangePicker(document.getElementById('input-6'), {
selectionMode: 'single',
visibleMonthsCount: 6,
monthLayout: 'grid',
gridRows: 2,
gridColumns: 3,
dateFormatMask: 'YYYY-MM-DD',
onSelect: (detail) => {
document.getElementById('output-6').textContent = `Selected: ${detail.formattedValue}`;
}
});
Create pickers on-the-fly based on user actions.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
let pickerCount = 0;
document.getElementById('add-picker-btn').addEventListener('click', () => {
pickerCount++;
const input = document.createElement('input');
input.type = 'text';
input.className = 'demo-input';
input.placeholder = 'YYYY-MM-DD';
// ... append label + input + output to the page ...
const picker = new DateRangePicker(input, {
selectionMode: 'single',
dateFormatMask: 'YYYY-MM-DD',
onSelect: (detail) => { output.textContent = `Selected: ${detail.formattedValue}`; }
});
});
All available options you can pass to the DateRangePicker constructor.
import { DateRangePicker } from '@keenmate/web-daterangepicker';
const picker = new DateRangePicker(inputElement, {
// Selection
selectionMode: 'single' | 'range', // Default: 'single'
// Display
visibleMonthsCount: 2, // Default: 1 for single, 2 for range
monthLayout: 'horizontal' | 'grid', // Default: 'horizontal'
gridRows: 2, gridColumns: 3, // Required if monthLayout is 'grid'
// Format
dateFormatMask: 'YYYY-MM-DD',
displayFormatMask: 'dd/mm/yyyy',
// Positioning
positioningMode: 'floating' | 'inline',
calendarPlacement: 'bottom-start',
container: document.body,
// Trigger
calendarOpenTrigger: 'focus' | 'typing' | 'manual',
// Date Restrictions
minDate: new Date('2025-01-01'),
maxDate: new Date('2025-12-31'),
disabledWeekdays: [0, 6],
disabledDates: [new Date('2025-12-25')],
disabledDatesHandling: 'allow' | 'block' | 'split' | 'individual',
// Internationalization
locale: 'en' | 'de' | 'fr' | 'es' | 'auto',
weekStartDay: 0 | 1 | 'auto',
customStrings: { today: 'Today', clear: 'Clear', apply: 'Apply' },
monthNames: ['Jan', 'Feb', '...'],
// Callbacks
onSelect: (detail) => console.log('Selected:', detail),
beforeDateSelectCallback: async (selection) => ({ action: 'accept' }),
formatSummaryCallback: (data) => `${data.nights} nights selected`,
getDateMetadataCallback: (date) => ({ badgeText: '!', badgeClass: 'custom' }),
renderDayCallback: (date, metadata) => `<div>${date.getDate()}</div>`
});
(pick a date anywhere on this page)