<input type="date">

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

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

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

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

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

Datepicker UI in firefox

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

入力欄に入力された日付の値を表す DOMString です。日付の書式は HTML で使われる日付や時刻の形式日付の文字列で説明しています。

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

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

一点気を付けなければならないことは、表示される日付の書式は実際の value とは異なるということです。 — 表示される日付形式は、ユーザーのブラウザーに設定されたロケールに基づいて選択されるのに対し、日付の value は常に yyyy-mm-dd の書式です。

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

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

このコード typedate である最初の <input> 要素を探し、値を 2017-06-01 (2017年6月1日) に設定します。

追加の属性

すべての <input> 型で共通する属性に加え、 date 型の入力欄は次の属性にも対応しています。

属性 説明
max 受け付ける最も遅い日付
min 受け付ける最も早い日付
step 上下の矢印で値を調整する時や、検証に使用する刻み値

max

受け付ける最新の日付です。要素に入力された value がこの日付よりも後の場合、要素は制約の検証に失敗します。 max 属性の値が yyyy-MM-dd の書式に従う妥当な文字列でない場合、要素は最大値を持ちません。

この値は min 属性で指定されたものより後か、同じ日付を指定する必要があります。

min

受け付ける最古の日付です。これより前の日付の場合、要素は制約の検証に失敗します。 min 属性の値が yyyy-MM-dd の書式に従う妥当な文字列でない場合、要素は最小値を持ちません。

この値は max 属性で指定されたものより前か、同じ日付を指定する必要があります。

step

step 属性は値が吸着する粒度を指定する数値、または後述する特殊な値 any です。刻みの基準値に等しい値 (指定されていれば min、そうでなければ value、どちらも設定されていなければ適切な既定値) のみが妥当となります。

文字列値の any は刻みがなく、どの値でも許可されることを意味します (minmax など、他の制約に制限されます)。

メモ: ユーザーがデータを入力したときには刻みの設定には吸着せず、ユーザーエージェントは直近の妥当な値、同じ距離の値の選択肢が二つあった場合は、正の方向の推奨値に丸められます。

date 入力欄では、 step の値は日数で指定され、 86,400,000 が乗じられます (ミリ秒単位の数値であるため)。 step の既定値は 1 であり、1日を表します。

anystep 属性の値として指定すると、 date 入力欄では 1 を設定したのと同じ効果になります。

date 入力欄の使用

日付入力は一見すると便利に見えます。日付の選択に簡単なユーザーインターフェイスを提供し、サーバーに送信するデータの書式をユーザーのロケールに関係なく正規化してくれます。しかし、ブラウザーの対応が限定されているため、 <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;
    var isLeap = new Date(year, 1, 29).getMonth() == 1;
    isLeap ? 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"> の定義
勧告

ブラウザーの互換性

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung Internet
type="date"Chrome 完全対応 20Edge 完全対応 12Firefox 完全対応 57IE 未対応 なしOpera 完全対応 11Safari 未対応 なし
補足
未対応 なし
補足
補足 The input type is recognized, but there is no date-specific control. See bug 119175.
WebView Android 完全対応 ありChrome Android 完全対応 ありFirefox Android 完全対応 57Opera Android 完全対応 11Safari iOS 完全対応 5Samsung Internet Android 完全対応 あり

凡例

完全対応  
完全対応
未対応  
未対応
実装ノートを参照してください。
実装ノートを参照してください。

関連情報