date 型の <input> 要素は、中身を自動的に検証するテキストボックスまたは特殊な日付選択インターフェイスを使用して、ユーザーに日付を入力させる入力フィールドを生成します。結果の値には年、月、日が含まれますが、時刻は含まれません。 time 及び datetime-local 入力型は時刻や日付と時刻の入力に対応しています。

コントロールのユーザーインターフェイスは、一般にブラウザ―によってまちまちです。現時点で対応は不安定であり、詳細はブラウザーの対応を参照してください。対応していないブラウザーでは、このコントロールは単純な <input type="text"> に格下げされます。

日付を選択するカスタムインターフェイスに対応したブラウザーの中で、 Chrome/Opera の日付コントロールは次のように表示されます。

Edge の日付コントロールは次のように表示されます。

Firefox の日付コントロールは次のように表示されます。

Datepicker UI in firefox

YYYY-MM-DD 形式で日付を表現する DOMString、または空欄
イベント change および input
対応する共通属性 autocomplete, list, readonly, step
IDL 属性 list, value, valueAsDate, valueAsNumber
メソッド select(), stepDown(), stepUp()

入力欄に入力された日付の値を表す DOMString です。次のように、 value 属性に日付を入れることで、入力欄の既定値を設定することができます。

<input id="date" type="date" value="2017-06-01">

一つ注意するべき点として、表示される日付の形式は実際の value とは異なります。表示される日付の形式は、ブラウザーのロケールの設定に基づいて選択されますが、日付の value は常に yyyy-mm-dd の形式です。

次の例のように、 input 要素の value プロパティを用いて、 JavaScript で日付の値を取得したり設定した入りすることができます。

var dateControl = document.querySelector('input[type="date"]');
dateControl.value = '2017-06-01';

このコードでは、 typedate である最初の <input> 要素を探し、その値を日付 2017-06-01 に設定します。

日付入力の使用

日付入力は一見すると便利に見えます。日付の選択に簡単なユーザーインターフェイスを提供し、サーバーに送信するデータの書式をユーザーのロケールに関係なく正規化してくれます。しかし、ブラウザーの対応が限定されているため、 <input type="date"> には問題があります。

<input type="date"> の基本的な使い方と少し複雑な使い方を見てみてから、その後でブラウザーの対応の問題を緩和するアドバイスを提供しましょう(ブラウザーの対応の扱い を参照してください)。もちろん、できれば今後ブラウザーの対応がもっと普遍的になり、この問題が消滅することを願います。

日付入力の基本的な使用

もっとも単純な <input type="date"> の使用方法は、次のように基本的な <input><label> 要素の組み合わせです。

<form>
  <div>
    <label for="bday">誕生日を入力してください。</label>
    <input type="date" id="bday" name="bday">
  </div>
</form>

日付の最大値と最小値の設定

min 及び max 属性を使用して、ユーザーが選択できる日付を制限することができます。次の例では、日付の最小値を 2017-04-01 に、日付の最大値を 2017-04-30 に設定しています。

<form>
  <div>
    <label for="party">希望するパーティーの日を選んでください。</label>
    <input type="date" id="party" name="party" min="2017-04-01" max="2017-04-30">
  </div>
</form>

この結果は、2017年の4月の日付のみが選択できるようになります。文字列値の「日」の部分のみが編集可能となり、日付選択ウィジェットで4月以外にスクロールすることはできなくなります。

メモ: step 属性を使用すると、日付が加算するたびに飛ばす日数を設定できるはずです(例えば、土曜日のみを選択できるようにしたい場合など)。しかし、執筆時点でどの実装も正しく動作していないようです。

入力欄の寸法の制御

<input type="date">size のような寸法に関する属性には対応していません。寸法を変更する必要がある場合は、 CSS を使用する必要があります。

検証

既定で、 <input type="date"> は入力された値の検証を行いません。ユーザーインターフェイスの実装は一般的に、日付でないものの入力をさせないからです。これは便利です。しかし、それでも入力欄を空のままにしたり、(text 型にフォールバックするブラウザーにおいて)無効な日付(例えば4月32日など)を入力したりすることが可能です。

min 及び max を使用して有効な日付を制限すると(日付の最大値と最小値の設定を参照)、対応しているブラウザーは設定された範囲の外の日付を送信しようとすると、エラーを表示するでしょう。しかし、この制限が行われるのはユーザーの機器が日付選択に完全に対応している場合のみなので、値がこの日付の範囲内にあるかどうかの結果をチェックしなければならないでしょう。

さらに、 required 属性を使用して、日付の入力を必須にすることができます。この場合も、空の日付欄を送信しようとするとエラーが表示されるでしょう。これは、少なくとも、多くのブラウザーで動作するはずです。

例を見てみましょう。ここで日付の最小値と最大値を設定し、入力欄を必須にしました。

<form>
  <div>
    <label for="party">Choose your preferred party date (required, April 1st to 20th):</label>
    <input type="date" id="party" name="party" min="2017-04-01" max="2017-04-20" required>
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit">
  </div>
</form>

不完全な日付(または設定した範囲を外れた日付)を送信しようとすると、ブラウザーはエラーを表示します。例を実行してみましょう。

対応しているブラウザーで入力しなかった場合のスクリーンショットです。

上記の例の CSS です。 CSS の :valid 及び :invalid プロパティを使用して、現在の値が有効かどうかに基づいてスタイルを設定しています。アイコンは入力欄そのものではなく、入力欄の隣の <span> に置くようにしないと、 Chrome ではコントロールの内側にコンテンツを生成するので、正しく整形したり表示したりすることができません。

div {
    margin-bottom: 10px;
    display: flex;
    align-items: center;
}

label {
  display: inline-block;
  width: 300px;
}

input:invalid+span:after {
    content: '✖';
    padding-left: 5px;
}

input:valid+span:after {
    content: '✓';
    padding-left: 5px;
}

重要: HTML のフォーム検証は、入力されたデータが正しい形式であることを保証するスクリプトの代用にはなりません。 HTML を調整して検証をくぐり抜けたり、完全に削除したりすることはとても簡単にできます。 HTML を完全にバイパスし、サーバーに直接データを送信することも可能です。サーバー側のコードが受信したデータの検証に失敗した場合、不適切な形式のデータ(または大きすぎるデータ、間違った種類のデータなど)が送信された場合に災害が発生するおそれがあります。

ブラウザーの対応の扱い

前述のように、現時点で日付入力を書く上で一番の問題はブラウザーの対応です。 Android 版 Firefox の日付選択はこの例のように表示されます。

対応していないブラウザーでは、文字列入力欄に安全に格下げされますが、これはユーザーインターフェイスの一貫性(表示されるコントロールが異なること)とデータの扱いの両方で問題を生みます。

2番目の問題はより深刻です。すでに述べたように、日付入力では、実際の値が常に yyyy-mm-dd の書式で正規化されます。一方文字列入力欄では、既定でブラウザーは日付がどの書式で入力されるかの認識がなく、以下のように人間が日付を書く様々な方法で入力される可能性があります。

  • ddmmyyyy
  • dd/mm/yyyy
  • mm/dd/yyyy
  • dd-mm-yyyy
  • mm-dd-yyyy
  • Month dd yyyy

これを回避する方法の一つは、日付入力に pattern 属性を付けることです。日付入力はこれを使用しないので、文字列入力にフォールバックされたときは使用します。例えば、次の例を未対応のブラウザーで見てみてください。

<form>
  <div>
    <label for="bday">誕生日を入力してください:</label>
    <input type="date" id="bday" name="bday" required pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}">
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit">
  </div>
</form>

nnnn-nn-nn のパターン(n は数字の0から9)に一致しない文字列を入力して送信しようとすると、エラーメッセージが表示される(そして入力欄が無効として強調表示される)のが分かるでしょう。もちろん、これでユーザーが無効な日付を入力したり、(yyyy-mm-dd を求めている時に) yyyy-dd-mm のような不正な書式の日付が入力されたりすることを止めることはできません。ですから、まだ問題があります。

ブラウザーに依存しない方法によってフォームで日付を扱う最善の方法は、現時点では年月日を別々なコントロール(<select> 要素が一般的です。以下の実装を見てください)にするか、 jQuery date picker のような JavaScript ライブラリを使用することです。

この例では、日付を選択するユーザーインターフェイスの要素を2組生成します。ネイティブの <input type="date"> による選択と、ネイティブの入力に対応しない古いブラウザー向けの、3つの <select> 要素による日付選択です。

HTML

HTML は次のようになります。

<form>
    <div class="nativeDatePicker">
      <label for="bday">誕生日を入力してください:</label>
      <input type="date" id="bday" name="bday">
      <span class="validity"></span>
    </div>
    <p class="fallbackLabel">誕生日を入力してください:</p>
    <div class="fallbackDatePicker">
      <span>
        <select id="year" name="year">
        </select>
        <label for="year">年</label>
      </span>
      <span>
        <select id="month" name="month">
          <option selected>1</option>
          <option>2</option>
          <option>3</option>
          <option>4</option>
          <option>5</option>
          <option>6</option>
          <option>7</option>
          <option>8</option>
          <option>9</option>
          <option>10</option>
          <option>11</option>
          <option>12</option>
        </select>
        <label for="month">月</label>
      </span>
      <span>
        <select id="day" name="day">
        </select>
        <label for="day">日</label>
      </span>
    </div>
</form>

月は(常に同じなので)ハードコーディングされていますが、年と日の値は、現在の年、および現在選択されている年と月によってそれぞれ動的に生成されます(どのように動作するかについての詳細な説明は、以下のコードのコメントを参照してください)。

JavaScript

もう一つの面白い部分は、機能の検出コードです。ブラウザーが <input type="date"> に対応しているかどうかを検出するために、新たな <input> 要素を生成し、その typedate に設定して、すぐに type に何が設定されたかをチェックします。対応していないブラウザーでは、 date 型が text 型へフォールバックされるため、 text が返されます。 <input type="date"> に対応していない場合は、ネイティブの日付選択を非表示にしてフォールバック用の (<select>) による選択ユーザーインターフェイスを表示します。

// 変数を定義
var nativePicker = document.querySelector('.nativeDatePicker');
var fallbackPicker = document.querySelector('.fallbackDatePicker');
var fallbackLabel = document.querySelector('.fallbackLabel');

var yearSelect = document.querySelector('#year');
var monthSelect = document.querySelector('#month');
var daySelect = document.querySelector('#day');

// 最初はフォールバックを非表示にする
fallbackPicker.style.display = 'none';
fallbackLabel.style.display = 'none';

// 新しい日付入力が文字列入力にフォールバックされるかどうか
var test = document.createElement('input');
test.type = 'date';

// もし文字列入力になるならば、 if() {} ブロックの中のコードを実行する
if(test.type === 'text') {
  // ネイティブの日付選択を隠してフォールバック版を表示
  nativePicker.style.display = 'none';
  fallbackPicker.style.display = 'block';
  fallbackLabel.style.display = 'block';

  // 日と年を動的に生成する
  // (月は常に同じなのでハードコーディング)
  populateDays(monthSelect.value);
  populateYears();
}

function populateDays(month) {
  // 日の <select> から現在の一連の <option> 要素を削除し、
  // 挿入のための準備をする
  while(daySelect.firstChild){
    daySelect.removeChild(daySelect.firstChild);
  }

  // 挿入する日数を保持する変数を作成
  var dayNum;

  // 31 または 30 日
  if(month === '1' || month === '3' || month === '5' || month === '7' || month === '8' || month === '10' || month === '12') {
    dayNum = 31;
  } else if(month === '4' || month === '6' || month === '9' || month === '11') {
    dayNum = 30;
  } else {
  // 2月の場合は、閏年かどうかを計算する
    var year = yearSelect.value;
    (year - 2016) % 4 === 0 ? dayNum = 29 : dayNum = 28;
  }

  // 日付の <select> に正しい数の新しい <option> 要素を
  for(i = 1; i <= dayNum; i++) {
    var option = document.createElement('option');
    option.textContent = i;
    daySelect.appendChild(option);
  }

  // 前回の日が既に設定されていたら、 daySelect の値を
  // 日に設定し、年を変えたときに1に戻ることを避ける
  if(previousDay) {
    daySelect.value = previousDay;

    // 前回設定されていた日が大きい数字、つまり31であった場合、
    // そして日数が少ない月(例えば2月)を選択した場合、
    // コードのこの部分で空欄を表示するのではなく、一番大きな日が
    // 選択されるようにする
    if(daySelect.value === "") {
      daySelect.value = previousDay - 1;
    }

    if(daySelect.value === "") {
      daySelect.value = previousDay - 2;
    }

    if(daySelect.value === "") {
      daySelect.value = previousDay - 3;
    }
  }
}

function populateYears() {
  // 今年を数字として取得
  var date = new Date();
  var year = date.getFullYear();

  // 今年から100年前までの年が <select> で選択できるようにする
  for(var i = 0; i <= 100; i++) {
    var option = document.createElement('option');
    option.textContent = year-i;
    yearSelect.appendChild(option);
  }
}

// 年や月の <select> 値が変更されたら、 populateDays() を
// 再実行して日数を調整する
yearSelect.onchange = function() {
  populateDays(monthSelect.value);
}

monthSelect.onchange = function() {
  populateDays(monthSelect.value);
}

//日数を保存
var previousDay;

// 以前どの日が設定されていたかを保存する
// 使い方は populateDays() を参照
daySelect.onchange = function() {
  previousDay = daySelect.value;
}

メモ: 53週ある年もあることを忘れないでください(年あたりの週数を参照)。商品のアプリを開発するときはこれを念頭に置いておく必要があります。

仕様策定状況

仕様書 策定状況 コメント
HTML Living Standard
<input type="date"> の定義
現行の標準  
HTML5
<input type="date"> の定義
勧告  

ブラウザーの対応

 

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応201257 なし11 なし1
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応 あり あり ?57115 ?

1. The input type is recognized, but there is no date-specific control.

 

関連情報

ドキュメントのタグと貢献者

このページの貢献者: silverskyvicto, mfuji09, homirun
最終更新者: silverskyvicto,