← Back to Examples

🔨 JavaScript Instantiation

Create and configure date pickers programmatically for dynamic applications

About this page
This page demonstrates the standalone 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.

Why Use JavaScript Instantiation?

While the web component approach (<web-daterangepicker>) is convenient for static configurations, JavaScript instantiation is useful when:

  • You need to create pickers dynamically based on user actions or data
  • You're working with existing HTML inputs that can't be replaced
  • You prefer a programmatic API over HTML attributes
  • You need to attach pickers to inputs created by other frameworks
⚠️ Important: When using JavaScript instantiation, you must create a regular <input type="text"> element first, then pass it to the DateRangePicker constructor. The class will attach the calendar functionality to your existing input.

⚠️ Critical: CSS Requirements

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.

🚨 Common Mistake: If you only see plain numbers in a grid without any styling, you forgot to import the CSS! This is the #1 issue when using JavaScript instantiation.

Method 1: Import CSS in JavaScript (Recommended for Bundlers)

// 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);

Method 2: Link CSS in HTML (For CDN or Simple Setups)

<!-- 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>

Method 3: Import SCSS Source (For Custom Builds)

// 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);

Method 4: Programmatic Injection (Alternative)

// Inject styles programmatically (no CSS import needed!)
import { DateRangePicker } from '@keenmate/web-daterangepicker';

DateRangePicker.injectGlobalStyles();

const picker = new DateRangePicker(inputElement, options);
💡 Why is this necessary?
The web component (<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.

1. Basic Single Date Picker

Create a simple single-date picker with default options.

No date selected
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}`;
  }
});

2. Date Range Picker with Multiple Months

Create a range picker with 2 visible months and custom configuration.

No range selected
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}`;
  }
});

3. With Date Restrictions

Configure min/max dates, disabled weekends, and specific disabled dates.

Weekends disabled, limited to current month
No date selected
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}`;
  }
});

4. Different Date Formats

Create pickers with various date format masks.

No date selected
No date selected
// 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}`;
  }
});

5. Inline Calendar (No Input Field)

Create a standalone calendar without an input field.

No date selected
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()}`;
  }
});
💡 Tip: When using positioningMode: 'inline', pass null as the first argument and specify a container in the options.

6. Grid Layout (2×3)

Display 6 months in a grid layout for easier navigation.

No date selected
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}`;
  }
});

7. Dynamic Creation

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}`; }
  });
});

8. Complete Options Reference

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>`
});
🔌 Server round-trip
0
The LiveView server saw 0 event(s) from the wrapper.
(pick a date anywhere on this page)