React DatePickerの使い方|日付選択UIを10分で実装
React DatePickerライブラリを使った日付選択UIの実装方法を詳しく解説。基本的な使い方から日本語化、カスタマイズまで初心者向けに説明します。
みなさん、Reactで日付選択機能を実装したいと思ったことはありませんか?
「予約システムで日付を選択させたい」 「フォームに生年月日入力欄を追加したい」 「期間指定の検索機能を作りたい」
そんな疑問を持ったことはありませんか?
実は、React DatePickerを使えば、わずか10分で実用的な日付選択UIが作れるんです。 この記事では、react-datepickerライブラリを使って日付選択機能を実装する方法を詳しく解説します。
基本的な使い方から日本語化、カスタマイズまで、初心者の方でも分かりやすく説明していきます。 一緒に素敵な日付選択UIを作ってみましょう!
React DatePickerって何?
まず、React DatePickerの基本的な特徴を理解しましょう。
ライブラリの特徴
React DatePickerは、最も人気の高いReact用日付選択ライブラリです。 簡単に言うと、「カレンダーから日付を選ぶ機能」を簡単に追加できるライブラリです。
こんな特徴があります。
- 軽量で高性能: アプリの動作が重くならない
- 豊富なカスタマイズ: 見た目や機能を自由に変更可能
- アクセシビリティ対応: 誰でも使いやすい設計
- TypeScript対応: 型の補完が効く
- 日本語対応: 日本語表示もバッチリ
週間ダウンロード数は約200万回という、信頼性の高いライブラリです。
インストール方法
まず、プロジェクトにライブラリをインストールしましょう。
npm install react-datepicker
これだけで準備完了です! 簡単ですよね。
基本的なセットアップ
次に、基本的な使い方を見てみましょう。
import React, { useState } from 'react';
import DatePicker from 'react-datepicker';
// CSSファイルも忘れずにインポート
import 'react-datepicker/dist/react-datepicker.css';
const BasicDatePicker = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
return (
<div>
<h3>日付を選択してください</h3>
<DatePicker
selected={selectedDate}
onChange={(date) => setSelectedDate(date)}
/>
<p>選択された日付: {selectedDate?.toLocaleDateString('ja-JP')}</p>
</div>
);
};
export default BasicDatePicker;
このコードの動作を確認してみましょう。
まず、必要なライブラリをインポートします。
DatePicker
がメインのコンポーネントで、CSSファイルも忘れずに読み込みます。
useState
で現在選択されている日付を管理しています。
初期値はnew Date()
で今日の日付を設定しています。
DatePicker
コンポーネントには2つのプロパティを設定しています。
selected
で現在選択されている日付を表示し、onChange
で日付が変更されたときの処理を定義しています。
最後に、選択された日付を日本語形式で表示しています。
「意外と簡単!」と思いませんか? この基本形を覚えれば、あとは機能を追加していくだけです。
基本的な実装パターン
実際のプロジェクトでよく使われるパターンを見てみましょう。
パターン1: シンプルな日付選択
最もシンプルな日付選択の実装です。
const SimpleDatePicker = () => {
const [startDate, setStartDate] = useState(new Date());
return (
<div className="date-picker-container">
<label htmlFor="date-input">日付選択:</label>
<DatePicker
id="date-input"
selected={startDate}
onChange={(date) => setStartDate(date)}
dateFormat="yyyy/MM/dd"
placeholderText="日付を選択してください"
/>
</div>
);
};
このコードでは、より実用的な設定を追加しています。
label
要素で入力欄の説明を追加し、htmlFor
とid
で関連付けています。
これにより、アクセシビリティが向上します。
dateFormat
で日付の表示形式を指定しています。
yyyy/MM/dd
で「2024/01/15」のような形式になります。
placeholderText
で、何も選択されていないときのヒントテキストを設定しています。
パターン2: 期間選択(開始日〜終了日)
予約システムや検索機能でよく使われる期間選択です。
const DateRangePicker = () => {
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(null);
return (
<div className="date-range-container">
<div className="date-input-group">
<label>開始日:</label>
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
selectsStart
startDate={startDate}
endDate={endDate}
placeholderText="開始日を選択"
/>
</div>
<div className="date-input-group">
<label>終了日:</label>
<DatePicker
selected={endDate}
onChange={(date) => setEndDate(date)}
selectsEnd
startDate={startDate}
endDate={endDate}
minDate={startDate}
placeholderText="終了日を選択"
/>
</div>
{startDate && endDate && (
<p>
選択期間: {startDate.toLocaleDateString('ja-JP')}
~ {endDate.toLocaleDateString('ja-JP')}
</p>
)}
</div>
);
};
期間選択では、2つの日付を管理する必要があります。
startDate
とendDate
という2つのstateを用意しています。
開始日の設定では、selectsStart
プロパティを使います。
これにより、期間選択の開始日として動作します。
終了日の設定では、selectsEnd
プロパティを使います。
さらに、minDate={startDate}
で、開始日より前の日付を選択できないようにしています。
最後に、両方の日付が選択されているときだけ、選択期間を表示しています。
パターン3: 時刻選択付き
日時を両方選択したい場合の実装です。
const DateTimePicker = () => {
const [selectedDateTime, setSelectedDateTime] = useState(new Date());
return (
<div>
<label>日時選択:</label>
<DatePicker
selected={selectedDateTime}
onChange={(date) => setSelectedDateTime(date)}
showTimeSelect
timeFormat="HH:mm"
timeIntervals={15}
timeCaption="時刻"
dateFormat="yyyy/MM/dd HH:mm"
placeholderText="日時を選択してください"
/>
<p>
選択された日時: {selectedDateTime?.toLocaleString('ja-JP')}
</p>
</div>
);
};
時刻選択を有効にするには、showTimeSelect
プロパティを追加します。
timeFormat
で時刻の表示形式を指定しています。
HH:mm
で24時間形式の「14:30」のような表示になります。
timeIntervals
で時刻の選択間隔を指定します。
15
なら15分刻みで選択できます。
timeCaption
で時刻選択部分のラベルを設定しています。
dateFormat
を変更して、日時両方を表示するようにしています。
「結構簡単に色々な機能が付けられるんですね!」 そうなんです。基本的な使い方を覚えれば、あとは設定を変えるだけで様々な機能を追加できます。
日本語化とローカライゼーション
日本のユーザーにとって使いやすくするための設定を見てみましょう。
日本語表示の設定
カレンダーの月名や曜日を日本語で表示する方法です。
import { registerLocale, setDefaultLocale } from 'react-datepicker';
import ja from 'date-fns/locale/ja';
// 日本語ロケールを登録
registerLocale('ja', ja);
const JapaneseDatePicker = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
return (
<DatePicker
selected={selectedDate}
onChange={(date) => setSelectedDate(date)}
locale="ja" // 日本語に設定
dateFormat="yyyy年MM月dd日"
placeholderText="日付を選択してください"
/>
);
};
まず、日本語ロケールを使うための準備をします。
registerLocale
で日本語設定を登録しています。
locale="ja"
を設定することで、カレンダーの表示が日本語になります。
月名が「1月」「2月」のようになり、曜日も「日」「月」のように表示されます。
dateFormat
も日本語に合わせて「yyyy年MM月dd日」の形式に変更しています。
カスタム日本語ラベル
さらに細かい日本語設定をする場合の例です。
const CustomJapaneseDatePicker = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
return (
<DatePicker
selected={selectedDate}
onChange={(date) => setSelectedDate(date)}
locale="ja"
dateFormat="yyyy年MM月dd日"
// 年・月の選択ドロップダウンを表示
showMonthDropdown
showYearDropdown
yearDropdownItemNumber={10}
scrollableYearDropdown
// 日本語のプレースホルダー
placeholderText="年月日を入力または選択"
// 今日ボタンの日本語化
todayButton="今日"
/>
);
};
この設定では、より使いやすい日本語インターフェースを実現しています。
showMonthDropdown
とshowYearDropdown
で、年と月をドロップダウンで選択できるようになります。
遠い過去や未来の日付を選ぶときに便利です。
yearDropdownItemNumber
で、年のドロップダウンに表示する項目数を指定しています。
todayButton="今日"
で、今日の日付に戻るボタンを日本語で表示しています。
「これで日本のユーザーにとって使いやすくなりますね!」 そうですね。ローカライゼーションは、ユーザー体験を大きく向上させる重要な要素です。
実用的なカスタマイズ
実際のプロジェクトで使える、より高度なカスタマイズを見てみましょう。
バリデーション付きフォーム
日付の妥当性をチェックするフォームの実装です。
const ValidatedDateForm = () => {
const [birthDate, setBirthDate] = useState(null);
const [errors, setErrors] = useState({});
const validateDate = (date) => {
const newErrors = {};
if (!date) {
newErrors.birthDate = '生年月日を選択してください';
} else {
const today = new Date();
const age = today.getFullYear() - date.getFullYear();
if (date > today) {
newErrors.birthDate = '未来の日付は選択できません';
} else if (age > 120) {
newErrors.birthDate = '正しい生年月日を入力してください';
}
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validateDate(birthDate)) {
console.log('送信成功:', birthDate);
alert('登録が完了しました');
}
};
return (
<form onSubmit={handleSubmit} className="date-form">
<div className="form-group">
<label htmlFor="birth-date">生年月日 *</label>
<DatePicker
id="birth-date"
selected={birthDate}
onChange={(date) => {
setBirthDate(date);
validateDate(date);
}}
locale="ja"
dateFormat="yyyy年MM月dd日"
showMonthDropdown
showYearDropdown
yearDropdownItemNumber={80}
scrollableYearDropdown
placeholderText="生年月日を選択"
maxDate={new Date()} // 今日以前のみ選択可能
// エラー時のスタイル
className={errors.birthDate ? 'error' : ''}
/>
{errors.birthDate && (
<span className="error-message">{errors.birthDate}</span>
)}
</div>
<button type="submit" className="submit-button">
登録
</button>
</form>
);
};
このフォームでは、しっかりとしたバリデーションを実装しています。
validateDate
関数で、日付の妥当性をチェックしています。
未選択、未来の日付、120歳を超える年齢などをエラーとして検出します。
maxDate={new Date()}
で、今日以前の日付のみ選択可能にしています。
これにより、未来の日付を選択できないようになります。
エラーがある場合は、エラーメッセージを表示し、入力欄にエラーのスタイルを適用します。
「フォームのバリデーションも簡単に実装できるんですね!」 そうです。適切なバリデーションは、ユーザー体験を大きく向上させます。
営業日のみ選択可能なカレンダー
営業日のみを選択できるカレンダーの実装です。
const BusinessDayPicker = () => {
const [selectedDate, setSelectedDate] = useState(null);
// 営業日かどうかを判定する関数
const isBusinessDay = (date) => {
const day = date.getDay();
// 土曜日(6)、日曜日(0)を除外
return day !== 0 && day !== 6;
};
// 祝日リスト(簡易版)
const holidays = [
new Date(2024, 0, 1), // 元日
new Date(2024, 4, 3), // 憲法記念日
new Date(2024, 4, 4), // みどりの日
new Date(2024, 4, 5), // こどもの日
// 他の祝日も追加可能
];
const isHoliday = (date) => {
return holidays.some(holiday =>
holiday.toDateString() === date.toDateString()
);
};
const isSelectableDate = (date) => {
return isBusinessDay(date) && !isHoliday(date);
};
return (
<div>
<h3>配送日選択(営業日のみ)</h3>
<DatePicker
selected={selectedDate}
onChange={(date) => setSelectedDate(date)}
locale="ja"
dateFormat="yyyy年MM月dd日(eee)"
minDate={new Date()} // 今日以降のみ
filterDate={isSelectableDate} // 営業日のみ選択可能
placeholderText="配送日を選択してください"
// 土日祝日を強調表示
dayClassName={(date) => {
if (!isSelectableDate(date)) {
return 'unavailable-day';
}
return undefined;
}}
/>
{selectedDate && (
<p>
配送予定日: {selectedDate.toLocaleDateString('ja-JP')}
({selectedDate.toLocaleDateString('ja-JP', { weekday: 'long' })})
</p>
)}
</div>
);
};
この実装では、営業日のみを選択可能にしています。
isBusinessDay
関数で、土日を除外する判定を行っています。
date.getDay()
で曜日を取得し、0(日曜)と6(土曜)を除外しています。
holidays
配列で祝日を定義し、isHoliday
関数で祝日判定を行っています。
filterDate
プロパティで、選択可能な日付を制限しています。
営業日かつ祝日でない日付のみが選択可能になります。
dayClassName
で、選択不可な日付に特別なスタイルを適用しています。
「これで営業日のみの配送日選択が実現できますね!」 はい。このような業務要件に応じたカスタマイズも簡単に実装できます。
高度な実装例
さらに実用的な機能を組み合わせた例を見てみましょう。
予約システムの例
予約システムでよく使われる、日時と時間枠を組み合わせた実装です。
const ReservationDatePicker = () => {
const [reservationDate, setReservationDate] = useState(null);
const [timeSlot, setTimeSlot] = useState('');
const [availableSlots, setAvailableSlots] = useState([]);
// 利用可能な時間枠
const timeSlots = [
'09:00', '10:00', '11:00', '13:00',
'14:00', '15:00', '16:00', '17:00'
];
// 予約済み時間枠(実際はAPIから取得)
const bookedSlots = {
'2024-01-15': ['09:00', '14:00'],
'2024-01-16': ['10:00', '11:00', '15:00']
};
const handleDateChange = (date) => {
setReservationDate(date);
setTimeSlot('');
if (date) {
const dateString = date.toISOString().split('T')[0];
const booked = bookedSlots[dateString] || [];
const available = timeSlots.filter(slot => !booked.includes(slot));
setAvailableSlots(available);
}
};
const handleReservation = () => {
if (reservationDate && timeSlot) {
const reservationInfo = {
date: reservationDate.toLocaleDateString('ja-JP'),
time: timeSlot
};
console.log('予約情報:', reservationInfo);
alert(`予約を受け付けました
日時: ${reservationInfo.date} ${reservationInfo.time}`);
}
};
return (
<div className="reservation-container">
<h3>予約日時選択</h3>
<div className="date-selection">
<label>予約日:</label>
<DatePicker
selected={reservationDate}
onChange={handleDateChange}
locale="ja"
dateFormat="yyyy年MM月dd日(eee)"
minDate={new Date()}
maxDate={new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)} // 30日後まで
placeholderText="予約日を選択"
// 土日を除外
filterDate={(date) => {
const day = date.getDay();
return day !== 0 && day !== 6;
}}
/>
</div>
{reservationDate && (
<div className="time-selection">
<label>時間枠:</label>
<select
value={timeSlot}
onChange={(e) => setTimeSlot(e.target.value)}
className="time-select"
>
<option value="">時間を選択してください</option>
{availableSlots.map(slot => (
<option key={slot} value={slot}>
{slot}
</option>
))}
</select>
{availableSlots.length === 0 && (
<p className="no-slots">この日は予約枠がありません</p>
)}
</div>
)}
<button
onClick={handleReservation}
disabled={!reservationDate || !timeSlot}
className="reservation-button"
>
予約する
</button>
</div>
);
};
この予約システムでは、複数の機能を組み合わせています。
日付が選択されると、handleDateChange
関数が実行されます。
選択された日付に応じて、利用可能な時間枠を計算し、availableSlots
を更新します。
bookedSlots
で予約済みの時間枠を管理しています。
実際のプロジェクトでは、APIから取得することが多いでしょう。
時間枠の選択にはselect
要素を使用し、利用可能な時間のみを表示しています。
「予約システムみたいな複雑な機能も作れるんですね!」 そうです。基本的な機能を組み合わせることで、実用的なシステムを構築できます。
検索フィルターでの期間指定
検索システムでよく使われる期間指定フィルターの実装です。
const SearchWithDateRange = () => {
const [searchParams, setSearchParams] = useState({
startDate: null,
endDate: null,
keyword: ''
});
const [searchResults, setSearchResults] = useState([]);
const handleSearch = async () => {
// 検索パラメータの構築
const params = {
keyword: searchParams.keyword,
startDate: searchParams.startDate?.toISOString().split('T')[0],
endDate: searchParams.endDate?.toISOString().split('T')[0]
};
console.log('検索パラメータ:', params);
// 実際の検索処理(APIコール等)
// const results = await searchAPI(params);
// setSearchResults(results);
// デモ用の結果
setSearchResults([
{ id: 1, title: '検索結果1', date: '2024-01-15' },
{ id: 2, title: '検索結果2', date: '2024-01-20' }
]);
};
const clearDateRange = () => {
setSearchParams(prev => ({
...prev,
startDate: null,
endDate: null
}));
};
return (
<div className="search-container">
<h3>期間指定検索</h3>
<div className="search-form">
<div className="keyword-input">
<label>キーワード:</label>
<input
type="text"
value={searchParams.keyword}
onChange={(e) => setSearchParams(prev => ({
...prev,
keyword: e.target.value
}))}
placeholder="検索キーワード"
/>
</div>
<div className="date-range">
<label>期間:</label>
<div className="date-inputs">
<DatePicker
selected={searchParams.startDate}
onChange={(date) => setSearchParams(prev => ({
...prev,
startDate: date
}))}
locale="ja"
dateFormat="yyyy/MM/dd"
placeholderText="開始日"
selectsStart
startDate={searchParams.startDate}
endDate={searchParams.endDate}
/>
<span className="date-separator">〜</span>
<DatePicker
selected={searchParams.endDate}
onChange={(date) => setSearchParams(prev => ({
...prev,
endDate: date
}))}
locale="ja"
dateFormat="yyyy/MM/dd"
placeholderText="終了日"
selectsEnd
startDate={searchParams.startDate}
endDate={searchParams.endDate}
minDate={searchParams.startDate}
/>
</div>
<button onClick={clearDateRange} className="clear-button">
期間クリア
</button>
</div>
<button onClick={handleSearch} className="search-button">
検索
</button>
</div>
<div className="search-results">
{searchResults.map(result => (
<div key={result.id} className="result-item">
<h4>{result.title}</h4>
<p>日付: {result.date}</p>
</div>
))}
</div>
</div>
);
};
この検索システムでは、キーワードと期間を組み合わせた検索が可能です。
searchParams
というオブジェクトで、すべての検索条件を一元管理しています。
handleSearch
関数で、検索パラメータを構築し、実際の検索処理を行います。
日付はISO形式の文字列に変換して、APIに送信することが多いでしょう。
clearDateRange
関数で、期間指定のみをクリアできるようにしています。
「検索システムにも簡単に期間指定機能を追加できるんですね!」 はい。このような実用的な機能も、基本的な使い方の組み合わせで実現できます。
スタイリングとカスタマイズ
見た目をカスタマイズする方法を見てみましょう。
基本的なCSS設定
React DatePickerの外観を調整するCSSの例です。
/* react-datepicker のカスタマイズ */
.react-datepicker-wrapper {
width: 100%;
}
.react-datepicker__input-container input {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.react-datepicker__input-container input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}
/* 選択不可の日付 */
.unavailable-day {
color: #ccc !important;
background-color: #f5f5f5 !important;
}
/* エラー時のスタイル */
.error {
border-color: #dc3545 !important;
}
.error-message {
color: #dc3545;
font-size: 12px;
margin-top: 4px;
display: block;
}
/* フォームスタイル */
.date-form .form-group {
margin-bottom: 20px;
}
.date-form label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.submit-button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.submit-button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
このCSSでは、React DatePickerの基本的な見た目を整えています。
入力欄のスタイルを統一し、フォーカス時のハイライトを追加しています。 選択不可な日付は、グレーアウト表示にしています。
エラー時の赤い枠線と、エラーメッセージのスタイルも定義しています。
「CSSでしっかりとスタイルを整えることで、プロフェッショナルな見た目になりますね!」 その通りです。適切なスタイリングは、ユーザー体験を大きく向上させます。
まとめ
React DatePickerを使った日付選択UIの実装について、たくさんのパターンを見てきました。
重要なポイント
これらのポイントを押さえておきましょう。
- 基本実装:
selected
、onChange
の基本プロパティを理解する - 日本語化:
locale
設定で日本語表示に対応する - バリデーション: 適切な制限とエラーハンドリングを実装する
- カスタマイズ: 業務要件に応じた機能拡張を行う
- スタイリング: CSSでデザインを統一する
実装時のコツ
実装を成功させるためのコツをお伝えします。
- 必要な機能から段階的に実装する
- ユーザビリティを重視した設計にする
- レスポンシブ対応とアクセシビリティを考慮する
- 適切なバリデーションでユーザー体験を向上させる
React DatePickerは柔軟性が高く実用的なライブラリです。 基本的な使い方から始めて、要件に応じて機能を拡張していくことで、高品質な日付選択UIを効率的に実装できます。
「これで日付選択機能が作れそうです!」 そうですね。まずは基本的な実装から始めて、少しずつ機能を追加していってください。
ぜひこの記事を参考に、あなたのプロジェクトに最適な日付選択機能を実装してみてください!