Поле ввода даты с календарём на чистом JavaScript

Компонент поддерживает маску ДД.ММ.ГГГГ / ДД.ММ.ГГ, ISO-значение в data-атрибуте, валидацию, ограничения min/max/disabled dates, popup-позиционирование, мобильную модалку и настройку через data-*. Стили календаря изолированы через Shadow DOM.

Полноценный пример

Попробуйте ручной ввод, выбор в календаре, кнопку “Сегодня”, “Очистить” и disabled-даты.
Доступно для ввода 80 лет до и 2 года после текущего (настраивается).
value: —; iso: —; invalid: false

Варианты использования

Сокращённый год

25 будет интерпретирован как 2025.

Внешняя иконка

Внутренняя иконка

Календарь открывается только по внутренней иконке. Иконка стилизуется через CSS variables.
<input
  data-date-picker
  data-open-trigger="internal-icon"
  data-internal-icon="true"

  style="
    --dp-icon-size: 36px;

    --dp-accent: #0f766e;
    --dp-radius: 18px;
  "
>

Без внутренней иконки

Календарь открывается только при фокусе или клике на поле. Внутренняя иконка полностью отключена.
<input
  data-date-picker
  data-open-trigger="input"
  placeholder="ДД.ММ.ГГГГ"
>

Ограниченный диапазон

Можно выбрать только даты мая 2026.

Кастомная тема

Цвета календаря настраиваются через CSS variables на самом input.

Настройка списка годов

Если min/max не указаны, список годов строится от текущий год - 5 до текущий год + 3.

Примеры кода

Минимальное подключение

<input data-date-picker placeholder="ДД.ММ.ГГГГ">

<script src="./date-picker.js"></script>

Полная настройка через data-атрибуты

<input
  data-date-picker
  data-format="dd.mm.yyyy"
  data-min="2024-01-01"
  data-max="2027-12-31"
  data-disabled-dates="2026-01-01,2026-01-07"
  data-position="bottom"
  data-open-trigger="all"
  data-internal-icon="true"
  data-mobile-breakpoint="768"
  data-year-past="80"
  data-year-future="20"
  placeholder="ДД.ММ.ГГГГ"
>

Кастомизация темы

<input
  data-date-picker
  style="
    --dp-accent: #7c3aed;
    --dp-radius: 18px;
    --dp-bg: #faf5ff;
    --dp-control-bg: #ede9fe;
    --dp-hover-bg: #ddd6fe;
    --dp-border: #c4b5fd;
  "
>

Ручная инициализация

const input = document.querySelector('#date');

const picker = new VanillaDatePicker(input, {
  format: 'dd.mm.yy',
  shortYearBase: 2000,
  min: '2026-01-01',
  max: '2026-12-31',
  disabledDates: ['2026-05-09'],
  yearPast: 10,
  yearFuture: 5,
  internalIcon: true,
  position: 'bottom'
});

picker.setDate('2026-05-21');
picker.open();
picker.close();
picker.clear();
picker.destroy();

Как читать состояние

const input = document.querySelector('[data-date-picker]');

console.log(input.value);           // 21.05.2026
console.log(input.dataset.dateIso); // 2026-05-21
console.log(input.dataset.dateInvalid); // true / false

input.addEventListener('date-picker:change', (event) => {
  console.log(event.detail);
});

Управление триггерами открытия

data-open-trigger="all"
Открытие по input, внутренней и внешней иконке

data-open-trigger="input"
Только по input

data-open-trigger="internal-icon"
Только по внутренней иконке

data-open-trigger="external-icon"
Только по внешней иконке

Адаптивное поле

Поле занимает всю доступную ширину контейнера до 520px, а внутренняя иконка остаётся внутри поля.
<input
  style="width: 100%; max-width: 520px;"
  data-date-picker
  data-internal-icon="true"
  data-open-trigger="all"
  placeholder="ДД.ММ.ГГГГ"
>