Webパーツ辞典

日付ピッカーDate picker

日付を入れる欄に、月のカレンダーを開いて選べる仕組みを付けたもの。予約日のように、曜日を見ながら決めたい日付に使う。

表示例

年/月/日 で入力

アイコン: Font Awesome 7 Free(fa-solid / fa-regular)

別名・英語表記

  • カレンダー入力
  • デートピッカー
  • 日付選択
  • カレンダーピッカー
  • 日付入力欄
  • カレンダーから選ぶ
  • Date picker

実装例

<div class="x-date-picker">
  <div class="x-date-picker__top">
    <label class="x-date-picker__l" for="x-date-picker-i">予約日</label>
    <span class="x-date-picker__fmt" id="x-date-picker-fmt">年/月/日 で入力</span>
  </div>
  <div class="x-date-picker__row">
    <input class="x-date-picker__i" id="x-date-picker-i" type="text" name="date" inputmode="numeric"
           value="2026/09/28" aria-describedby="x-date-picker-fmt">
    <button class="x-date-picker__b" type="button" aria-label="カレンダーから選ぶ"
            aria-haspopup="dialog" aria-expanded="true" aria-controls="x-date-picker-d">
      <i class="fa-solid fa-calendar-days" aria-hidden="true"></i>
    </button>
  </div>
  <!-- 見本なので開いた状態。実際は開いたときだけ表示し、aria-modal="true" を付けてフォーカスを選択中の日へ移す -->
  <div class="x-date-picker__d" id="x-date-picker-d" role="dialog" aria-labelledby="x-date-picker-h">
    <div class="x-date-picker__nav">
      <button class="x-date-picker__m" type="button" aria-label="前の月">
        <i class="fa-solid fa-chevron-left" aria-hidden="true"></i>
      </button>
      <h2 class="x-date-picker__h" id="x-date-picker-h" aria-live="polite">2026年9月</h2>
      <button class="x-date-picker__m" type="button" aria-label="次の月">
        <i class="fa-solid fa-chevron-right" aria-hidden="true"></i>
      </button>
    </div>
    <table class="x-date-picker__g" role="grid" aria-labelledby="x-date-picker-h">
      <thead>
        <tr>
          <th scope="col" abbr="日曜日" class="x-date-picker__sun">日</th><th scope="col" abbr="月曜日">月</th>
          <th scope="col" abbr="火曜日">火</th><th scope="col" abbr="水曜日">水</th>
          <th scope="col" abbr="木曜日">木</th><th scope="col" abbr="金曜日">金</th>
          <th scope="col" abbr="土曜日" class="x-date-picker__sat">土</th>
        </tr>
      </thead>
      <tbody>
        <tr><td></td><td></td><td tabindex="-1">1</td><td tabindex="-1">2</td><td tabindex="-1">3</td><td tabindex="-1">4</td><td tabindex="-1">5</td></tr>
        <tr><td tabindex="-1">6</td><td tabindex="-1">7</td><td tabindex="-1">8</td><td tabindex="-1">9</td><td tabindex="-1">10</td><td tabindex="-1">11</td><td tabindex="-1">12</td></tr>
        <tr><td tabindex="-1">13</td><td tabindex="-1">14</td><td tabindex="-1">15</td><td tabindex="-1">16</td><td tabindex="-1">17</td><td tabindex="-1">18</td><td tabindex="-1">19</td></tr>
        <tr><td tabindex="-1">20</td><td tabindex="-1">21</td><td tabindex="-1">22</td><td tabindex="-1">23</td><td tabindex="-1">24</td><td tabindex="-1" aria-current="date">25</td><td tabindex="-1">26</td></tr>
        <tr><td tabindex="-1">27</td><td tabindex="0" aria-selected="true">28</td><td tabindex="-1">29</td><td tabindex="-1">30</td><td></td><td></td><td></td></tr>
      </tbody>
    </table>
  </div>
</div>

AIへの指示文

「日付ピッカー(Date picker)」を実装してください。

## これは何か
日付を入れる欄に、月のカレンダーを開いて選べる仕組みを付けたもの。予約日のように、曜日を見ながら決めたい日付に使う。

## 使いどころ
- 予約日・配達希望日のように、曜日や今日からの近さを見ながら選びたいとき
- 選べない日(定休日・過去の日)をカレンダーの上で見せたいとき

## 実装の要件
- label + input(直接入力)+ button[aria-haspopup=dialog][aria-expanded] + div[role=dialog] > table[role=grid]
- 曜日の見出しは th に abbr="日曜日" を付け、省略しない名前でも読めるようにする
- 選べない日は aria-disabled="true" にして見た目も薄くし、理由(定休日など)を文字で添える
- min / max で選べる範囲を決める(input type="date" でも同じ属性が使える)
- 生年月日にカレンダーを使わない。数十年前まで月送りを繰り返させることになる。年・月・日を別の欄にするか、数字で直接入れてもらう
- 直接入力の道を残す。カレンダーだけにすると、日付が決まっている人ほど遅くなる
- 入力の形式の揺れ(2026/09/28・2026-9-28・全角数字)を受け止める。受け付けない形式があるなら、欄の近くに形式を書いておく
- 和暦で入れてもらうなら、内部では西暦で持ち、表示と入力だけ和暦にする。元号の切り替わり(令和元年は2019年5月1日から)をまたぐ日付に注意する
- 日付だけの文字列 "2026-09-28" を JavaScript の new Date() に渡すと UTC の0時として扱われ、UTC より遅れる時間帯(南北アメリカなど)では前日の日付になる。年・月・日の数値から組み立てる
- 週の始まり(日曜か月曜か)を利用者の慣れに合わせる。日本のカレンダーは日曜始まりが多い

## アクセシビリティの要件
- まず input type="date" で足りるか考える。カレンダーとキーボード操作はブラウザが用意し、送られる値は常に yyyy-mm-dd の形になる。ただし見た目と表示の形式(ブラウザや OS の言語設定に従う)は変えられない
- 独自のカレンダーを作るなら、開くボタンに aria-label(「カレンダーから選ぶ」)を付け、開いたら role="dialog" のパネルで選択中の日へフォーカスを移す。閉じたらボタンへ戻す
- 日付の並びは role="grid" の表にし、矢印キーで1日・1週、PageUp / PageDown で1か月、Home / End で週の端へ動かす(WAI-ARIA APG の Date Picker Dialog)
- 選んでいる日は aria-selected="true"、今日は aria-current="date" で示す。見た目は塗りと枠線のように、形でも区別する
- 月の見出しに aria-live="polite" を付け、月を送ったときに「2026年10月」と伝わるようにする

## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。

```html
<div class="x-date-picker">
  <div class="x-date-picker__top">
    <label class="x-date-picker__l" for="x-date-picker-i">予約日</label>
    <span class="x-date-picker__fmt" id="x-date-picker-fmt">年/月/日 で入力</span>
  </div>
  <div class="x-date-picker__row">
    <input class="x-date-picker__i" id="x-date-picker-i" type="text" name="date" inputmode="numeric"
           value="2026/09/28" aria-describedby="x-date-picker-fmt">
    <button class="x-date-picker__b" type="button" aria-label="カレンダーから選ぶ"
            aria-haspopup="dialog" aria-expanded="true" aria-controls="x-date-picker-d">
      <i class="fa-solid fa-calendar-days" aria-hidden="true"></i>
    </button>
  </div>
  <!-- 見本なので開いた状態。実際は開いたときだけ表示し、aria-modal="true" を付けてフォーカスを選択中の日へ移す -->
  <div class="x-date-picker__d" id="x-date-picker-d" role="dialog" aria-labelledby="x-date-picker-h">
    <div class="x-date-picker__nav">
      <button class="x-date-picker__m" type="button" aria-label="前の月">
        <i class="fa-solid fa-chevron-left" aria-hidden="true"></i>
      </button>
      <h2 class="x-date-picker__h" id="x-date-picker-h" aria-live="polite">2026年9月</h2>
      <button class="x-date-picker__m" type="button" aria-label="次の月">
        <i class="fa-solid fa-chevron-right" aria-hidden="true"></i>
      </button>
    </div>
    <table class="x-date-picker__g" role="grid" aria-labelledby="x-date-picker-h">
      <thead>
        <tr>
          <th scope="col" abbr="日曜日" class="x-date-picker__sun">日</th><th scope="col" abbr="月曜日">月</th>
          <th scope="col" abbr="火曜日">火</th><th scope="col" abbr="水曜日">水</th>
          <th scope="col" abbr="木曜日">木</th><th scope="col" abbr="金曜日">金</th>
          <th scope="col" abbr="土曜日" class="x-date-picker__sat">土</th>
        </tr>
      </thead>
      <tbody>
        <tr><td></td><td></td><td tabindex="-1">1</td><td tabindex="-1">2</td><td tabindex="-1">3</td><td tabindex="-1">4</td><td tabindex="-1">5</td></tr>
        <tr><td tabindex="-1">6</td><td tabindex="-1">7</td><td tabindex="-1">8</td><td tabindex="-1">9</td><td tabindex="-1">10</td><td tabindex="-1">11</td><td tabindex="-1">12</td></tr>
        <tr><td tabindex="-1">13</td><td tabindex="-1">14</td><td tabindex="-1">15</td><td tabindex="-1">16</td><td tabindex="-1">17</td><td tabindex="-1">18</td><td tabindex="-1">19</td></tr>
        <tr><td tabindex="-1">20</td><td tabindex="-1">21</td><td tabindex="-1">22</td><td tabindex="-1">23</td><td tabindex="-1">24</td><td tabindex="-1" aria-current="date">25</td><td tabindex="-1">26</td></tr>
        <tr><td tabindex="-1">27</td><td tabindex="0" aria-selected="true">28</td><td tabindex="-1">29</td><td tabindex="-1">30</td><td></td><td></td><td></td></tr>
      </tbody>
    </table>
  </div>
</div>
```

```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-date-picker,
.x-date-picker *:not([class*="fa-"]),
.x-date-picker *:not([class*="fa-"])::before,
.x-date-picker *:not([class*="fa-"])::after {
  box-sizing: border-box;
  /* 貼った先の既定の書体に引きずられないようにする。書体が変わると
     文字の幅と高さが変わり、枠のサイズまでずれる */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}

.x-date-picker {
  width: 232px;
  color: #1b2028;
}
.x-date-picker__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
}
.x-date-picker__l {
  font-size: 12px;
  font-weight: 700;
}
.x-date-picker__fmt {
  color: #5b6472;
  font-size: 11px;
}
.x-date-picker__row {
  display: flex;
  gap: 6px;
}
.x-date-picker__i {
  flex: 1 1 auto;
  min-width: 0;
  height: 40px;
  padding: 0 10px;
  border: 1px solid #7f8a99;
  border-radius: 8px;
  background: #fff;
  color: #1b2028;
  font: inherit;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.x-date-picker__b {
  width: 40px;
  height: 40px;
  flex: none;
  border: 1px solid #7f8a99;
  border-radius: 8px;
  background: #fff;
  color: #1b2028;
  cursor: pointer;
}
/* 実際のページでは position: absolute で入力欄の下に重ねる。見本は流れの中に置いている */
.x-date-picker__d {
  margin-top: 6px;
  padding: 6px 8px 8px;
  border: 1px solid #7f8a99;
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 6px 16px rgba(27, 32, 40, .12);
}
.x-date-picker__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 2px;
}
.x-date-picker__h {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
}
.x-date-picker__m {
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: #1b2028;
  font-size: 12px;
  cursor: pointer;
}
.x-date-picker__g {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.x-date-picker__g th {
  height: 20px;
  color: #5b6472;
  font-size: 10.5px;
  font-weight: 700;
}
.x-date-picker__g th.x-date-picker__sun,
.x-date-picker__g td:first-child {
  color: #b91c1c;
}
.x-date-picker__g th.x-date-picker__sat,
.x-date-picker__g td:last-child {
  color: #1d4ed8;
}
.x-date-picker__g td {
  height: 26px;
  padding: 0;
  border-radius: 6px;
  cursor: pointer;
}
.x-date-picker__g td:empty {
  cursor: default;
}
/* 今日は枠線で、選択中は塗りで示す。色だけに頼らず形も変える */
.x-date-picker__g td[aria-current="date"] {
  box-shadow: inset 0 0 0 1.5px #1b2028;
  font-weight: 700;
}
.x-date-picker__g td[aria-selected="true"] {
  background: #1d4ed8;
  color: #fff;
  font-weight: 700;
}
.x-date-picker__i:focus-visible,
.x-date-picker__b:focus-visible,
.x-date-picker__m:focus-visible,
.x-date-picker__g td:focus-visible {
  outline: 2px solid #1d4ed8;
  outline-offset: 1px;
}
```

## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。

使いどころ

  • 予約日・配達希望日のように、曜日や今日からの近さを見ながら選びたいとき
  • 選べない日(定休日・過去の日)をカレンダーの上で見せたいとき

注意点

  • 生年月日にカレンダーを使わない。数十年前まで月送りを繰り返させることになる。年・月・日を別の欄にするか、数字で直接入れてもらう
  • 直接入力の道を残す。カレンダーだけにすると、日付が決まっている人ほど遅くなる
  • 入力の形式の揺れ(2026/09/28・2026-9-28・全角数字)を受け止める。受け付けない形式があるなら、欄の近くに形式を書いておく
  • 和暦で入れてもらうなら、内部では西暦で持ち、表示と入力だけ和暦にする。元号の切り替わり(令和元年は2019年5月1日から)をまたぐ日付に注意する
  • 日付だけの文字列 "2026-09-28" を JavaScript の new Date() に渡すと UTC の0時として扱われ、UTC より遅れる時間帯(南北アメリカなど)では前日の日付になる。年・月・日の数値から組み立てる
  • 週の始まり(日曜か月曜か)を利用者の慣れに合わせる。日本のカレンダーは日曜始まりが多い

アクセシビリティの要点

  • まず input type="date" で足りるか考える。カレンダーとキーボード操作はブラウザが用意し、送られる値は常に yyyy-mm-dd の形になる。ただし見た目と表示の形式(ブラウザや OS の言語設定に従う)は変えられない
  • 独自のカレンダーを作るなら、開くボタンに aria-label(「カレンダーから選ぶ」)を付け、開いたら role="dialog" のパネルで選択中の日へフォーカスを移す。閉じたらボタンへ戻す
  • 日付の並びは role="grid" の表にし、矢印キーで1日・1週、PageUp / PageDown で1か月、Home / End で週の端へ動かす(WAI-ARIA APG の Date Picker Dialog)
  • 選んでいる日は aria-selected="true"、今日は aria-current="date" で示す。見た目は塗りと枠線のように、形でも区別する
  • 月の見出しに aria-live="polite" を付け、月を送ったときに「2026年10月」と伝わるようにする

見分け方

関連するパーツ