<input type="month">

<input> 要素の month 型は、ユーザーが年と月を入力できるようにする入力フィールドを作成し、年と月を簡単に入力できるようにします。 値は "YYYY-MM" の形式の文字列で、 YYYY は 4 桁の年、 MM は月の番号です。

試してみましょう

コントロールのユーザーインターフェイスは、一般にブラウザーによって異なります。現時点では対応が不安定であり、デスクトップ版の Chrome/Opera と Edge — および最新のバージョンのモバイルブラウザー — のみに利用可能な実装があります。 month 入力欄に対応していないブラウザーでは、コントロールは単純な <input type="text"> に格下げされますが、入力されたテキストが期待されている形式であることを保証するための自動検証が行われることもあります。

month に対応していないブラウザーを使用している場合のために、このスクリーンショットで Chrome と Opera でどのように見えるかを示します。 右端にある下向き矢印をクリックすると、年と月を選択できる日付選択が表示されます。

Chrome ブラウザーでの month コントロール

Microsoft Edge では、 month コントロールはこのように表示されます。

Edge ブラウザーの month コントロール

年と月を表す文字列、または空欄
イベント change および input
対応している共通属性 autocomplete, list, readonly, step
IDL 属性 value
DOM インターフェイス

HTMLInputElement

メソッド select(), stepDown(), stepUp()

文字列で、入力欄に入力された年と月の値を YYYY-MM (4 桁以上の年に続いてハイフン ("-")、続いて 2 桁の月) の形式で表します。 この入力型で使用される時刻の値の形式について詳しくは、 HTML で使われる日付や時刻の形式月の文字列をご覧ください。

既定値の設定

入力コントロールの既定値は、次のように value 属性に年と月を入れることで設定することができます。

<label for="bday-month">生まれた月は?</label>
 <input id="bday-month" type="month" name="bday-month" value="2001-06" />

一点気を付けなければならないことは、表示される日付の書式は実際の value とは異なるということです。多くのユーザーエージェントは、年と月をユーザーのオペレーティングシステムに設定されたロケールに適した形式で表示しますが、日付の value は常に yyyy-MM の書式です。

上記の値がサーバーへ送信された場合は、例えば、 bday-month=1978-06 のようになります。

JavaScript を使用した値の設定

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

<label for="bday-month">生まれた月は?</label>
<input id="bday-month" type="month" name="bday-month" />
const monthControl = document.querySelector('input[type="month"]');
monthControl.value = '2001-06';

追加の属性

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

list

list 属性の値は、同じ文書内にある <datalist> 要素の id です。 <datalist> は、この入力欄でユーザーに提案するための事前定義された値のリストを提供します。 リストの中の値のうち、この type と互換性のないものは、提案されるオプションには含まれません。 提供される値は提案であり、要件ではありません。ユーザーはこの定義済みリストから選択することも、異なる値を提供することもできます。

max

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

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

min

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

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

readonly

論理属性で、存在すれば、ユーザーが編集することができないことを表します。 しかし、 value は、 JavaScript コードから直接 HTMLInputElement.value プロパティを設定することで変更することができます。

メモ: 読み取り専用フィールドは値を持てないため、 requiredreadonly 属性も指定されている入力欄には効果がありません。

step

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

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

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

month 入力欄では、 step の値は月数で指定され、倍率は 1 です (数値も月単位であるため)。 step の既定値は 1 ヶ月です。

month 入力欄の使用

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

<input type="month"> の基本的な使い方と少し複雑な使い方を見てみてから、その後でブラウザーの互換性の問題を緩和するアドバイスを提供しましょう (ブラウザーの互換性の扱い を参照してください)。

月入力の基本的な使用

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

<form>
  <label for="bday-month">生まれた月を入力してください。</label>
  <input id="bday-month" type="month" name="bday-month" />
</form>

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

min および max 属性を使用して、ユーザーが選択できる日付の範囲を制限することができます。 次の例では、日付の最小値を 1900-01 に、日付の最大値を 2013-12 に指定しています。

<form>
  <label for="bday-month">生まれた月を入力してください。</label>
  <input
    id="bday-month"
    type="month"
    name="bday-month"
    min="1900-01"
    max="2013-12" />
</form>

次のような結果になります。

  • 1900 年 1 月から 2013 年 12 月までの間の月のみが選択できます。この範囲から外れた月は、コントロール内でスクロールできません。
  • 使用しているブラウザーによりますが、指定された範囲外の月が月選択で選択できないか (Edge など)、無効になるものの (検証 を参照) 選択できるか (Chrome など) だということが分かるでしょう。

入力欄の寸法の制御

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

検証

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

これを防ぐために、 minmax を用いて利用可能な日を制限することができ (日付の最大値と最小値の設定 を参照)、加えて required 属性を用いて、日付を入力することを必須にすることができます。 結果として、対応しているブラウザーは、範囲外の日付や空の日付フィールドを送信しようとするとエラーを表示します。

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

<form>
  <div>
    <label for="month">何月にいらっしゃいますか? (6 ~ 9 月)</label>
    <input
      id="month"
      type="month"
      name="month"
      min="2022-06"
      max="2022-09"
      required />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="フォームを送信" />
  </div>
</form>

年と月を指定せずに (または設定した範囲を外れた日付を) 送信しようとすると、ブラウザーはエラーを表示します。 例を実行してみましょう。

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

Chrome ブラウザーでの月が必要とするプロンプト

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

div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

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

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

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

ブラウザーの互換性の扱い

前述のように、現時点で日付入力を書く上で一番の問題は、多くの主要なブラウザーがまだすべてを実装している訳ではないということです。デスクトップでは Chrome/Opera と Edge のみが対応しており、モバイルでは多くの最新のブラウザーが対応しています。 例えば、 month の選択画面は Android 版 Chrome ではこのように表示されます。

Chrome for Android での日付ピッカー

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

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

  • mmyyyy (072022)
  • mm/yyyy (07/2022)
  • mm-yyyy (07-2022)
  • yyyy-mm (2022-07)
  • Month yyyy (July 2022)
  • ... などなど。

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

<form>
  <div>
    <label for="month">何月にいらっしゃいますか? (6 ~ 9 月)</label>
    <input
      id="month"
      type="month"
      name="month"
      min="2022-06"
      max="2022-09"
      required
      pattern="[0-9]{4}-[0-9]{2}" />
    <span class="validity"></span>
  </div>
  <div>
    <input type="submit" value="フォームを送信" />
  </div>
</form>

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

また、ユーザーが数ある日付形式の中で期待されるものがどれであるかを知らない可能性もあります。 後はその分の作業が残っています。

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

この例では、ユーザーが都市と月を選択できるよう設計されたユーザーインターフェイスの要素を2組作成します。 一つ目はネイティブの month 入力欄であり、もう一つは年と月を個別に選択することができる一組の <select> 要素で、まだ <input type="month"> に対応していないブラウザーのためのものです。

結果

HTML

年と月を入力するフォームはこのようになります。

<form>
  <div class="nativeDatePicker">
    <label for="month-visit">何月にいらっしゃいますか?</label>
    <input type="month" id="month-visit" name="month-visit">
    <span class="validity"></span>
  </div>
  <p class="fallbackLabel">何月にいらっしゃいますか?</p>
  <div class="fallbackDatePicker">
    <div>
      <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>
    </div>
  </div>
</form>

nativeDatePicker の ID がついた <div> は、年と月をリクエストするために month 入力欄を用いるのに対し、 fallbackDatePicker の ID がついた <div> は代わりに一組の <select> 要素を使用します。一つ目は年を、二つ目は月を入力します。

月を選択する <select> は、変化しないので月をハードコーディングしています (ローカライズの問題が残っていますが)。年に利用できる値は、現在の年に応じて動的に生成されます (どのように動作するかについての詳細な説明は、以下のコードのコメントを参照してください)。

JavaScript

どちらの方法を使用するかを選択し、非ネイティブの年の <select> に年の一覧を設定する JavaScript コードは以下の通りです。

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

// define variables
const nativePicker = document.querySelector('.nativeDatePicker');
const fallbackPicker = document.querySelector('.fallbackDatePicker');
const fallbackLabel = document.querySelector('.fallbackLabel');

const yearSelect = document.querySelector('#year');
const monthSelect = document.querySelector('#month');

// Hide fallback initially
fallbackPicker.style.display = 'none';
fallbackLabel.style.display = 'none';

// Test whether a new date input falls back to a text input or not
const test = document.createElement('input');

try {
  test.type = 'month';
} catch (e) {
  console.log(e.description);
}

// If it does, run the code inside the if () {} block
if (test.type === 'text') {
  // Hide the native picker and show the fallback
  nativePicker.style.display = 'none';
  fallbackPicker.style.display = 'block';
  fallbackLabel.style.display = 'block';

  // Populate the years dynamically
  // (the months are always the same, therefore hardcoded)
  populateYears();
}

function populateYears() {
  // Get the current year as a number
  const date = new Date();
  const year = date.getFullYear();

  // Make this year, and the 100 years before it available in the year <select>
  for (let i = 0; i <= 100; i++) {
    const option = document.createElement('option');
    option.textContent = year - i;
    yearSelect.appendChild(option);
  }
}

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

仕様書

Specification
HTML Standard
# month-state-(type=month)

ブラウザーの互換性

BCD tables only load in the browser

関連情報