DatePickerって色々あって迷う
HTML上での日付入力ってみんな一度は実装することはあるけど、実装頻度ってそんなにないですよね?
そのたびにどのライブラリを使うべきか、オプション諸々はどうやって書くか調べている気がします。
さすがに非効率なのでDatePickerマイベストを選定し、今後は迷わない様にしましょう!!(自分が)
とりあえず候補に選んだDatepickerを一つの画面にまとめてみました。
Datepicker候補全部入りページ
マイべストDatePickerの選定に当たっては、以下の3点を重視します。
- カレンダー上で指定日以外はノンアクティブにできること
- ユーザーが指定日以外をエディット欄から直接入力"できない"こと
- 導入のハードルの低さ
兎にも角にも、指定日のみカレンダーで選択できるかどうかが重要です。
どんな日付でも入力していいよー、ってケースはあまり無いのでは無いでしょうか。
趣味ユースでも業務でも、カレンダーで入力させたい日付は一定範囲に決まっていることが多いと思います。
それとエディット欄への直接入力でも指定した日付のみ入力されている状態にしたいところ。
予期しない日付が入るとバリデーションが必要ですし、入力する側もエラーで返すなら入力するときに制御してくれって思いますから。
候補1 jQuery UI Datepicker
reference
鉄板ライブラリ。
機能面で不足はほぼなし。
- ○:カレンダー上で指定日以外はノンアクティブにできること
用意された日付制御専用イベントにjavascriptで制御文を書けば可能 - △:ユーザーが指定日以外をエディット欄から直接入力"できない"こと
readonly="readonly"属性を指定する事で直接入力自体を抑止可能。
(その場合はhtml5対応が必須になる)
その場合はshowOn:"both"オプションをつけるとわかりやすいかな。 - ○:導入のハードルの低さ
- jquery依存
- 組織からの提供
- MIT License
候補2 Bootstrap Datepicker
github
オンラインデモ
Bootstrapに対応したDatepicker。
Bootstrapが提供しているDatepickerではない所に注意。
機能面で充実。
jquery+bootstrap依存、さらに個人デベロッパーの提供という事で、導入ハードルは若干高くなるか。
- ○:カレンダー上で指定日以外はノンアクティブにできること
用意された日付制御専用イベントにjavascriptで制御文を書けば可能 - △:ユーザーが指定日以外をエディット欄から直接入力"できない"こと
readonly="readonly"属性を指定する事で直接入力自体を抑止可能。 - △:導入のハードルの低さ
- jQuery 1.7.1+
- Bootstrap 2.0.4+
- 個人からの提供
- apache-2.0 License
候補3 inputタグの属性を"date"
HTML5から登場。
だが、機能面ではカレンダーとして必要最小限。
- ×:カレンダー上で指定日以外はノンアクティブにできること
最小日付、最大日付の指定は可能。しかし、土日のみ選択不可などの歯抜指定はできない。
入力候補日付リストをdatelistタグを使えると出せるけど、ただのリスト表示なのであまり嬉しくはない... - ×:ユーザーが指定日以外をエディット欄から直接入力"できない"こと
readonly="readonly"属性を指定するとカレンダーも表示できなくなるため、実質エディット欄からの入力を制御して日付を入力する手段は標準では無し。 - ◎:導入のハードルの低さ
- HTML5対応ブラウザで利用可能。
候補4 FlatPicker
[オンラインデモ] (https://chmln.github.io/flatpickr/)
jqueryやbootstrapに依存しない軽量ライブラリ。
機能も充実。
- ○:カレンダー上で指定日以外はノンアクティブにできること
用意された日付制御専用イベントにjavascriptで制御文を書けば可能 - ○:ユーザーが指定日以外をエディット欄から直接入力"できない"こと
直接入力は独自属性で制御できる。 - ○:導入のハードルの低さ
- 個人からの提供
- MIT License
##結論
薄々勘付いていたけど、これがベストDatePickerだ!とは言いづらい状況ですね。
"input type="date"だけが選外になりますが。
とはいえ、"input type=date"が一番ダメな子でも、min/maxの範囲内で初期表示をする事や、エディット欄からの矢印キー入力で範囲内の日付切り替えなどUX面で面白い機能があるのが意外。
ただ、そこを頑張っちゃうの?といった素材は悪くないけど残念な子感が強かったですね。
※追記 スマートフォンから見ると"type=date"は最小最大のレンジも効かなくなってしまう。全然ダメ。
他の候補はどれも手堅い。
複数人の開発者で触るサービスならメジャーなjquery-ui-datepickerかbootstrap-datepickerを導入済みのフレームワークに合わせて使うのが大人の対応でしょうか。
個人の趣味サービスならFlatpickerもいいですね。
最近はjquery不要論も唱えられているし、軽量で依存関係の薄さは魅力的です。
全部入りページコード
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>datepickers</title>
<!-- jquery-ui-datepicker に必要なモジュール-->
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/redmond/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<!-- bootstrap-datepickerに必要なモジュール -->
<!-- jqueryも使えるようにする必要があるけど、jquery-ui-datepickerの箇所で宣言しているのでコメントアウト -->
<!--<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/css/bootstrap-datepicker3.css"
integrity="sha256-LPN+eTpTPBqagrVriv55Ec3nMrGY4CdujtnzMBrAwMA=" crossorigin="anonymous"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/js/bootstrap-datepicker.min.js"
integrity="sha256-urCxMaTtyuE8UK5XeVYuQbm/MhnXflqZ/B9AOkyTguo=" crossorigin="anonymous"></script>
<!-- type=date datepikerに必要なモジュールはなし!-->
<!-- flatpickerに必要なモジュール -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/2.0.5/flatpickr.airbnb.min.css"
integrity="sha256-P4EMWC/blM8GTo9kBpQQ5EL+u6HdZc8grBCjKMB178w=" crossorigin="anonymous"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/2.0.5/flatpickr.min.js"
integrity="sha256-NlGYB5Z7QTXoBkWNBQmUmlrlTKrRZuSzpT22e4LVO0E=" crossorigin="anonymous"></script>
<script>
//今日と明後日のみ有効な日付とする
var today = new Date();
var dayAfterTomorrow = new Date();
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);
var availableDays = [today.toDateString(), dayAfterTomorrow.toDateString()];
//bootstrap-datepicker
$(function () {
//jquery-ui-datepickerとの競合防止
var bootstrapDatepicker = $.fn.datepicker.noConflict();
$.fn.bootstrapDP = bootstrapDatepicker;
//jquery-ui-datepickerがなければ$("#bootstrap-datepicker").datepicker({...と書けばよい
$("#bootstrap-datepicker").bootstrapDP({
format: 'yyyy/mm/dd',
autoclose: true,
startDate: today,
endDate: dayAfterTomorrow,
beforeShowDay: function (date) {
// return値はboolean
return (availableDays.indexOf(date.toDateString()) >= 0)
}
});
});
//jquery-ui-datepicker
$(function () {
$("#jquery-datepicker").datepicker({
altFormat: "yy-mm-dd",
showOn: "both",
minDate: today,
maxDate: dayAfterTomorrow,
beforeShowDay: function (date) {
// return値は配列[true, (クラス名)] class名 ""でデフォルト
return [availableDays.indexOf(date.toDateString()) >= 0, ""]
}
});
});
//input type=date DatePicker
$(function () {
//input type=dateのカレンダーにオプションを追加
//yyyy-mm-ddの形式じゃないと有効にならない...
$("#type-datepicker").attr("min", today.toISOString().slice(0, 10));
$("#type-datepicker").attr("max", dayAfterTomorrow.toISOString().slice(0, 10));
$("#selectlist").append('<option value="' + today.toISOString().slice(0, 10) + '"');
$("#selectlist").append('<option value="' + dayAfterTomorrow.toISOString().slice(0, 10) + '"');
});
//flatpickr
$(function () {
document.getElementById("flatpickr").flatpickr({
allowInput: false,
dateFormat: "Y/m/d",
minDate: today,
maxDate: dayAfterTomorrow,
enable: [
function (date) {
// return値はtrue/false
return availableDays.indexOf(date.toDateString()) >= 0
}
]
});
});
</script>
</head>
<body>
<h1>Datepickers</h1>
<!--readonly属性で直接入力の抑止-->
<h2>Jquery Ui DatePicker : <input type="text" id="jquery-datepicker" readonly="readonly"></h2>
<!--readonly属性で直接入力の抑止 -->
<h2>Bootstrap DatePicker : <input type="text" id="bootstrap-datepicker" readonly="readonly"></h2>
<!--readonly属性をつけるとカレンダーを開けない -->
<h2>input type=date DatePicker : <input type="date" id="type-datepicker" list="selectlist"></h2>
<datalist id="selectlist"></datalist>
<h2>flatpickr : <input type="text" id="flatpickr"></h2>
</body>
</html>