重い依存関係のないシンプルな日付・時刻ピッカー
プロジェクトで日付ピッカーが必要になるたびに、同じような展開になります。ネイティブのinput type="date"はブラウザごとに見た目が異なり、カスタマイズも面倒で、モバイル環境では動作が不安定です。シンプルなカレンダーを実装するためだけに、巨大なUIライブラリや古いラッパー、数十もの推移的依存関係を引っ張ってくるのは本末転倒です。
最近、vanilla-calendar-proリポジトリを見つけました。外部依存関係がゼロの干净なTypeScriptコンポーネントで、日付と時刻の選択ができます。プレーンなJavaScriptだけでなく、React、Vue、Svelteの中でも動作します。
内部構造と利便性について
このライブラリは、バンドルを肥大化させることなく、基本的なUIのニーズを満たすように構築されています。カレンダーは数キロバイトほどの軽量サイズですが、デザイナーやプロダクトマネージャーが必要とするほぼすべての機能を備えています。
特に注目すべき点は以下の通りです:
- 依存関係ゼロ。momentやdate-fnsのようなサードパーティの日付解析ユーティリティーは使用せず、内部でネイティブDateオブジェクトを使用しています。
- 柔軟な表示モード。カレンダーはページマークアップに直接埋め込むことも、inputクリック時にポップアップで開くこともできます。
- 範囲選択と複数月の同時表示。ホテルの予約、切符購入、アナリティクスダッシュボードなどに最適です。
- 組み込みの時刻ピッカー。時刻は24時間形式とAM/PMの両方で設定可能です。
- テーマ。すぐに使えるライトテーマとダークテーマが用意されており、カスタマイズは標準のCSS変数で行います。
クイックスタート
インストールは任意のパッケージマネージャーで標準的に行えます:
npm install vanilla-calendar-pro
バンドラーがない場合は、CDN経由でスクリプトとスタイルを直接インクルードできます。
マークアップでは、空のコンテナを作成するだけで済みます:
<div id="calendar"></div>
コードでの初期化はシンプルに記述できます:
import { VanillaCalendar } from 'vanilla-calendar-pro';
import 'vanilla-calendar-pro/build/vanilla-calendar.min.css';
const calendar = new VanillaCalendar('#calendar', {
settings: {
lang: 'ru-RU',
iso8601: true,
selection: {
day: 'multiple-ranged',
},
},
actions: {
clickDay(event, self) {
console.log('Выбранные даты:', self.selectedDates);
},
},
});
calendar.init();
設定ファイルを数行書くだけで、範囲選択サポートとロシア語ローカライズを備えた動作するカレンダーが完成します。
具体的なタスク向けのカスタマイズ
既成コンポーネントにありがちな問題として、標準的なデザインから逸脱しようとすると苦労することが挙げられます。vanilla-calendar-proでは、カスタムレイアウトを使用してDOM構造を必要に応じて再構築できます。
例えば、過去の日期を無効化して週末をブロックする必要がある場合は、設定を直接configオブジェクトに渡します:
const calendar = new VanillaCalendar('#calendar', {
settings: {
range: {
min: 'today',
disabled: ['2026-05-01', '2026-05-09'],
},
selection: {
time: 24,
},
},
actions: {
changeTime(event, self) {
console.log('Установленное время:', self.selectedTime);
},
},
});
calendar.init();
コンポーネントは動的なパラメータ更新を適切に処理します。アプリでユーザーが言語を切り替えた場合、ページ全体を再描画したりメモリリークを起こしたりすることなく、新しいオプションでupdateメソッドを呼び出すだけです。
フレームワークとの統合
名前にはvanillaが含まれていますが、著者はリアクティブライブラリとの使いやすさも確保しています。
Reactでは、カレンダーをフックに簡単にラップできます:
import { useEffect, useRef } from 'react';
import { VanillaCalendar } from 'vanilla-calendar-pro';
import 'vanilla-calendar-pro/build/vanilla-calendar.min.css';
export function DatePicker({ onSelect }) {
const containerRef = useRef(null);
useEffect(() => {
if (!containerRef.current) return;
const calendar = new VanillaCalendar(containerRef.current, {
actions: {
clickDay(event, self) {
onSelect(self.selectedDates);
},
},
});
calendar.init();
return () => {
calendar.destroy();
};
}, [onSelect]);
return <div ref={containerRef} />;
}
destroyメソッドはイベントハンドラーを適切にクリーンアップするため、アンマウント時にコンポーネントがメモリにゴミを残しません。
誰が役立つのか
このプロジェクトは、重厚なUI巨人と原始的なネイティブinputの間のギャップを埋めます。個人プロジェクト、ランディングページ、または大型のコンポーネントを引っ張ってきたくない管理パネルを作成している場合、優れた選択肢となります。
コードベースは完全に型付けされており、ソースはオープンで、公式サイトにあるドキュメントはすべてのAPIメソッドとスタイリングの例を丁寧に解説しています。次のスプリントのためにブックマークしておく価値があります。
関連プロジェクト