日付範囲ピッカーライブラリ比較
3つのアプローチで日付範囲を選択するUIを実装し、機能とスタイルを比較
共通の初期設定
各デモでは本日から7日後までを初期選択期間として設定しています。カレンダーから日付範囲を選択でき、選択結果がリアルタイムに表示されます。
{
"startDate": "2026-04-09",
"endDate": "2026-04-16",
"locale": "ja (日本語)"
}1. react-datepicker
最も人気のあるReact日付ピッカー — 豊富な機能と柔軟なカスタマイズ性
選択中:2026年4月9日 〜 2026年4月16日(7日間)
インラインカレンダー表示
April 2026
May 2026
特徴
- • ポップアップ・インライン両対応のカレンダー表示
- • 範囲選択・複数月表示・時刻選択に対応
- • ロケール設定で日本語表示が可能
- • 最小日・最大日の制限、除外日の設定が容易
インストール
npm install react-datepicker date-fns'use client';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import { useState } from 'react';
import { isAfter } from 'date-fns';
export function ReactDatePickerDemo() {
const [startDate, setStartDate] = useState<Date | null>(new Date());
const [endDate, setEndDate] = useState<Date | null>(
new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
);
return (
<div className="flex flex-col sm:flex-row gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">開始日</label>
<DatePicker
selected={startDate}
onChange={(date: Date | null) => {
setStartDate(date);
if (endDate && date && isAfter(date, endDate)) setEndDate(null);
}}
selectsStart
startDate={startDate}
endDate={endDate}
dateFormat="yyyy/MM/dd"
className="border border-gray-300 rounded px-3 py-2 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">終了日</label>
<DatePicker
selected={endDate}
onChange={(date: Date | null) => setEndDate(date)}
selectsEnd
startDate={startDate}
endDate={endDate}
minDate={startDate ?? undefined}
dateFormat="yyyy/MM/dd"
className="border border-gray-300 rounded px-3 py-2 text-sm"
/>
</div>
</div>
);
}🤖 AIプロンプトテンプレート
React + Tailwind CSSで、react-datepickerを使った日付範囲ピッカーを実装してください。
- 使用ライブラリ: react-datepicker、date-fns
- DatePicker コンポーネントで selectsStart/selectsEnd プロパティを使って開始日・終了日を個別に選択できること
- monthsShown={2} と selectsRange、inline プロパティでインラインの2ヶ月表示を実装すること
- locale="ja" で日本語表示し、dateFormat="yyyy/MM/dd" で書式化すること
- minDate プロパティで終了日に開始日以前を選択できないよう制限すること
- 選択された期間の日数をリアルタイムに計算して表示すること⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。
2. react-day-picker
軽量でアクセシブルなカレンダー — WAI-ARIA対応でモダンな設計
選択中:2026年4月9日 〜 2026年4月16日(7日間)
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
|---|---|---|---|---|---|---|
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
|---|---|---|---|---|---|---|
特徴
- • WAI-ARIAガイドラインに準拠した高いアクセシビリティ
- • シングル・複数・範囲選択モードを標準サポート
- • CSSカスタムプロパティでスタイル変更が容易
- • date-fnsベースでロケール対応が充実
インストール
npm install react-day-picker date-fns'use client';
import { DayPicker, type DateRange } from 'react-day-picker';
import 'react-day-picker/style.css';
import { useState } from 'react';
import { ja } from 'date-fns/locale';
export function ReactDayPickerDemo() {
const [range, setRange] = useState<DateRange | undefined>({
from: new Date(),
to: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
});
return (
<div>
<DayPicker
mode="range"
selected={range}
onSelect={setRange}
locale={ja}
numberOfMonths={2}
/>
{range?.from && range?.to && (
<p className="text-sm text-gray-600 mt-2">
選択期間: {range.from.toLocaleDateString('ja-JP')} 〜 {range.to.toLocaleDateString('ja-JP')}
</p>
)}
</div>
);
}🤖 AIプロンプトテンプレート
React + Tailwind CSSで、react-day-pickerを使った日付範囲ピッカーを実装してください。
- 使用ライブラリ: react-day-picker、date-fns
- DayPicker コンポーネントで mode="range" と numberOfMonths={2} を使った2ヶ月表示の範囲選択を実装すること
- DateRange 型で選択中の from/to を管理すること
- locale={ja} で日本語表示すること
- 「今週」「30日間」「90日間」「クリア」のプリセットボタンを実装すること
- 選択された期間の日数をリアルタイムに計算して表示すること⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。
3. カスタム実装(React + Tailwind CSS)
ライブラリ不要の完全カスタム実装 — ホバープレビューや2ヶ月表示を自作
2026年4月
2026年5月
選択期間:2026年4月9日 〜 2026年4月16日(7日間)
特徴
- • 外部ライブラリ不要で依存関係が最小限
- • ホバー時のプレビュー表示で直感的な範囲選択
- • プリセットボタン(今週・30日間など)を自由に追加可能
- • デザインの自由度が最も高い
インストール
npm install date-fns(日付計算用、カレンダーUIは自作)'use client';
import { useState } from 'react';
import { format, addMonths, subMonths, isSameDay, isAfter, isBefore } from 'date-fns';
import { ja } from 'date-fns/locale';
export function CustomDateRangePickerDemo() {
const [start, setStart] = useState<Date | null>(null);
const [end, setEnd] = useState<Date | null>(null);
const [hovered, setHovered] = useState<Date | null>(null);
const [viewMonth, setViewMonth] = useState(new Date());
const handleDayClick = (day: Date) => {
if (!start || (start && end)) {
setStart(day);
setEnd(null);
} else {
if (isAfter(day, start)) setEnd(day);
else { setEnd(start); setStart(day); }
}
};
const isInRange = (day: Date) => {
const rangeEnd = end ?? hovered;
if (!start || !rangeEnd) return false;
return isAfter(day, start) && isBefore(day, rangeEnd);
};
const daysInMonth = (year: number, month: number) =>
new Date(year, month + 1, 0).getDate();
const year = viewMonth.getFullYear();
const month = viewMonth.getMonth();
const firstDay = new Date(year, month, 1).getDay();
const days = daysInMonth(year, month);
return (
<div className="inline-block">
<div className="flex items-center justify-between mb-3">
<button onClick={() => setViewMonth(subMonths(viewMonth, 1))} className="px-2 py-1 text-sm">←</button>
<span className="font-semibold text-sm">{format(viewMonth, 'yyyy年M月', { locale: ja })}</span>
<button onClick={() => setViewMonth(addMonths(viewMonth, 1))} className="px-2 py-1 text-sm">→</button>
</div>
<div className="grid grid-cols-7 gap-1 text-center text-xs text-gray-500 mb-1">
{['日','月','火','水','木','金','土'].map(d => <span key={d}>{d}</span>)}
</div>
<div className="grid grid-cols-7 gap-1">
{Array.from({ length: firstDay }).map((_, i) => <span key={`e${i}`} />)}
{Array.from({ length: days }, (_, i) => {
const day = new Date(year, month, i + 1);
const isStart = start && isSameDay(day, start);
const isEnd = end && isSameDay(day, end);
const inRange = isInRange(day);
return (
<button
key={i}
onClick={() => handleDayClick(day)}
onMouseEnter={() => setHovered(day)}
onMouseLeave={() => setHovered(null)}
className={`text-sm py-1 rounded ${
isStart || isEnd ? 'bg-blue-600 text-white' : inRange ? 'bg-blue-100' : 'hover:bg-gray-100'
}`}
>
{i + 1}
</button>
);
})}
</div>
{start && (
<p className="text-xs text-gray-500 mt-2">
{format(start, 'yyyy/MM/dd')} {end ? `〜 ${format(end, 'yyyy/MM/dd')}` : '(終了日を選択)'}
</p>
)}
</div>
);
}🤖 AIプロンプトテンプレート
React + Tailwind CSSで、ライブラリ不要のカスタム日付範囲ピッカーを実装してください。 - 使用ライブラリ: date-fns(日付計算用)、React + Tailwind CSS(カレンダーUIは自作) - 2ヶ月分のカレンダーを横並びで表示し、開始日・終了日を順番にクリックして選択できること - onMouseEnter でホバー中の日付をプレビュー表示し、選択予定の範囲をハイライトすること - 選択中の範囲内の日付は bg-emerald-100、開始日・終了日は bg-emerald-600 でスタイリングすること - 「今週」「30日間」「クリア」のプリセットボタンと前月・翌月ナビゲーションを実装すること - 選択された期間の日数をリアルタイムに計算して表示すること
⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。
ライブラリ比較表
| 項目 | react-datepicker | react-day-picker | カスタム実装 |
|---|---|---|---|
| 範囲選択 | 内蔵 | 内蔵 | 自作 |
| 時刻選択 | 内蔵 | なし | 自作 |
| ポップアップ表示 | 内蔵 | 自作 | 自作 |
| アクセシビリティ | 基本的 | WAI-ARIA準拠 | 自作 |
| バンドルサイズ | 中程度(~40KB) | 小さい(~10KB) | 最小 |
| 学習コスト | 低 | 低〜中 | 中〜高(要件次第) |
| カスタマイズ性 | 中(CSS上書き) | 高(CSS変数) | 最高 |
| おすすめ用途 | フォーム内の日付入力全般 | アクセシビリティ重視のアプリ | 独自デザインが必要な場合 |
まとめ
react-datepicker — 最も手軽に日付範囲ピッカーを導入したい場合に最適。ポップアップ・インライン・時刻選択など豊富な機能が揃っている。
react-day-picker — アクセシビリティを重視する場合におすすめ。WAI-ARIA準拠で、CSSカスタムプロパティによるスタイル変更も容易。
カスタム実装 — ブランドに合わせた独自デザインが必要な場合や、ホバープレビューなど細かいUX制御をしたい場合に最適。