Calendar

A calendar component to be used to display and pick dates.

The calendar component relies on table elements, using specific aria roles and attributes so it is presented to the user as a grid.

Used in combination with the Input and components you can create complex data picking functionalities.

The calendar will expand to occupy the entire available width, in the examples bellow we se the minimum width for the calendar in the wrapping div, but this is not a rule and should be evaluated how much space is necessary for each use case. In many cases, setting a width is not even required as the component might just fit with your layout.

The component minimum width is spacing-1 * 46 (276px).

Accessibility

  1. The role at play is role="grid" added to the table element to ensure it is presented as a grid (not tabular data) to the end user.
  2. The second important aspect is writing out the full name of the abbreviated week days in the column headers. Add the full week day name as aria-label on each th element inside of the thead. This replaces the somewhat meaningless 2 letters with the actual name of the day for screen readers.
  3. Just visually disabling the buttons is not enough for the disabled days, you must also add aria-disabled="true" on the grid cell elements. Then you can either disable the button inside or replace the element with a span.
  4. The selected day should have not only the class modifier for appearance but also aria-selected="true" for screen readers.
September 2019
MoTuWeThFrSaSu
1
2 3 4
26 27 28 29
30
<div style="max-width:276px">
  <div class="flix-calendar">
    <div class="flix-calendar__month">
      <table class="flix-calendar__table" role="grid"><caption class="flix-calendar__caption">
          September 2019
        </caption><thead><tr><th class="flix-calendar__cell" aria-label="Monday">Mo</th><th class="flix-calendar__cell" aria-label="Tuesday">Tu</th><th class="flix-calendar__cell" aria-label="Wednesday">We</th><th class="flix-calendar__cell" aria-label="Thursday">Th</th><th class="flix-calendar__cell" aria-label="Friday">Fr</th><th class="flix-calendar__cell" aria-label="Saturday">Sa</th><th class="flix-calendar__cell" aria-label="Sunday">Su</th></tr></thead><tbody><tr><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">1</span>
            </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">2</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">3</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">4</span>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="5/9">5</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="6/9">6</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="7/9">7</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="8/9">8</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="9/9">9</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="10/9">10</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--selected" aria-selected="true">
              <button class="flix-calendar__btn" type="button" aria-label="11/9">11</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="12/9">12</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="13/9">13</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="14/9">14</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="15/9">15</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="16/9">16</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="17/9">17</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="18/9">18</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="19/9">19</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="20/9">20</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="21/9">21</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="22/9">22</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="23/9">23</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="24/9">24</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="25/9">25</button>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">26</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">27</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">28</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">29</span>
            </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">30</span>
            </td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td></tr></tbody></table>
    </div>
  </div>
</div>

With date range selection (aka: departure and return dates)

For range selection it is important to note the following:

  1. Add the aria-multiselectable="true" attribute to the grid (table element).
  2. The cell containing the selected departure day should have the --start modifier (in addition to the selected modifiers and attributes) to add the decorative arrows.
  3. When the return day is selected, add the --end modifier to the cell (as well as the selected modifiers).
  4. All cells in between should have --range modifier to add the highlight.

Notice you can show multiple months inside of the same calendar component, simply copy the calendar__month element and update the content to fit your calendar.

You can also show them side by side by using the --horizontal class modifier.

September 2019
MoTuWeThFrSaSu
1
2 3 4 5
October 2019
MoTuWeThFrSaSu
26 27
28 29 30
<div style="max-width:600px">
  <div class="flix-calendar flix-calendar--horizontal">
    <div class="flix-calendar__month">
      <table aria-live="polite" class="flix-calendar__table" role="grid" aria-multiselectable="true"><caption class="flix-calendar__caption">
          September 2019
        </caption><thead><tr><th class="flix-calendar__cell" aria-label="Monday">Mo</th><th class="flix-calendar__cell" aria-label="Tuesday">Tu</th><th class="flix-calendar__cell" aria-label="Wednesday">We</th><th class="flix-calendar__cell" aria-label="Thursday">Th</th><th class="flix-calendar__cell" aria-label="Friday">Fr</th><th class="flix-calendar__cell" aria-label="Saturday">Sa</th><th class="flix-calendar__cell" aria-label="Sunday">Su</th></tr></thead><tbody><tr><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">1</span>
            </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">2</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">3</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">4</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">5</span>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="6/9">6</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="7/9">7</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="8/9">8</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="9/9">9</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="10/9">10</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="11/9">11</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="12/9">12</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="13/9">13</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="14/9">14</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="15/9">15</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="16/9">16</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="17/9">17</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="18/9">18</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="19/9">19</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="20/9">20</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="21/9">21</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="22/9">22</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="23/9">23</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="24/9">24</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--start" aria-selected="true">
              <button class="flix-calendar__btn" type="button" aria-label="25/9">25</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="26/9">26</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="27/9">27</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="28/9">28</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="29/9">29</button>
            </td></tr><tr><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="30/9">30</button>
            </td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td></tr></tbody></table>
    </div>
    <div class="flix-calendar__month">
      <table aria-live="polite" class="flix-calendar__table" role="grid" aria-multiselectable="true"><caption class="flix-calendar__caption">
          October 2019
        </caption><thead><tr><th class="flix-calendar__cell" aria-label="Monday">Mo</th><th class="flix-calendar__cell" aria-label="Tuesday">Tu</th><th class="flix-calendar__cell" aria-label="Wednesday">We</th><th class="flix-calendar__cell" aria-label="Thursday">Th</th><th class="flix-calendar__cell" aria-label="Friday">Fr</th><th class="flix-calendar__cell" aria-label="Saturday">Sa</th><th class="flix-calendar__cell" aria-label="Sunday">Su</th></tr></thead><tbody><tr><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="1/10">1</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="2/10">2</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="3/10">3</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="4/10">4</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="5/10">5</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="6/10">6</button>
            </td></tr><tr><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="7/10">7</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="8/10">8</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--range">
              <button class="flix-calendar__btn" type="button" aria-label="9/10">9</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--end" aria-selected="true">
              <button class="flix-calendar__btn" type="button" aria-label="10/10">10</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="11/10">11</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="12/10">12</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="13/10">13</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="14/10">14</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="15/10">15</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="16/10">16</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="17/10">17</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="18/10">18</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="19/10">19</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="20/10">20</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="21/10">21</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="22/10">22</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="23/10">23</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="24/10">24</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="25/10">25</button>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">26</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">27</span>
            </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">28</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">29</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">30</span>
            </td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td></tr></tbody></table>
    </div>
  </div>
</div>

Calendar header with month and year pickers

The calendar-header wrapper should be added before the table element, as it contains the controls for the calendar.

The controls (could be button or select elements) will change the days rendered in the calendar when they change, so for that to be accessible there are some things we need to take care of:

  1. Add an id to the grid (table element) so you can associate it with its controls.
  2. Add aria-controls="{calendar-id}" to each element that is responsible for changing the calendar content.
  3. Add aria-live="polite" to the table, as it will enable screen readers to announce changes in the content of this element when they happen.

Now you can add your handlers to the controls and update the calendar days and caption as you wish.

The table header supports 2 different layouts: compact and birthday.

Compact header

Displays one month at a time, with one select box for month and year, and button for month navigation.

  • Use the button component with the following modifiers: secondary appearance and square display.
  • Use the select component with no visible label (add aria-label instead) and add the flix-calendar-header__select class name to it, to enable the calendar component to apply the necessary CSS adjustments.
  • You can also use the --flat modifier to remove border radius and box shadow where needed, we added this appearance modifier in the example bellow.
MoTuWeThFrSaSu
1
2 3 4
26 27 28 29
30
<div style="max-width:500px">
  <div class="flix-calendar flix-calendar--flat">
    <div class="flix-calendar__month">
      <div class="flix-calendar-header flix-calendar-header--compact">
        <button aria-label="Previous month" type="button" class="flix-btn flix-btn--secondary flix-btn--square flix-btn--disabled" aria-controls="calendar-grid">
          <flix-icon aria-hidden="true" name="arrow-left"></flix-icon>
        </button>
        <div class="flix-select flix-select--no-label flix-calendar-header__select">
          <select id="compact-picker" class="flix-select__field" aria-label="Select month and year" aria-controls="calendar-grid">
            <option value="2019-2">February 2019</option>
            <option value="2019-3">March 2019</option>
            <option value="2019-4">April 2019</option>
            <option value="2019-5">May 2019</option>
            <option value="2019-6">June 2019</option>
            <option value="2019-7">July 2019</option>
            <option value="2019-8">August 2019</option>
            <option value="2019-9">September 2019</option>
            <option value="2019-10">October 2019</option>
            <option value="2019-11">November 2019</option>
          </select>
        </div>
        <button aria-label="Next month" type="button" class="flix-btn flix-btn--secondary flix-btn--square" aria-controls="calendar-grid">
          <flix-icon aria-hidden="true" name="arrow-right"></flix-icon>
        </button>
      </div>
      <table id="calendar-grid" aria-live="polite" class="flix-calendar__table" role="grid"><thead><tr><th class="flix-calendar__cell" aria-label="Monday">Mo</th><th class="flix-calendar__cell" aria-label="Tuesday">Tu</th><th class="flix-calendar__cell" aria-label="Wednesday">We</th><th class="flix-calendar__cell" aria-label="Thursday">Th</th><th class="flix-calendar__cell" aria-label="Friday">Fr</th><th class="flix-calendar__cell" aria-label="Saturday">Sa</th><th class="flix-calendar__cell" aria-label="Sunday">Su</th></tr></thead><tbody><tr><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">1</span>
            </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">2</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">3</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">4</span>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="5/9">5</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="6/9">6</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="7/9">7</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="8/9">8</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="9/9">9</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="10/9">10</button>
            </td><td class="flix-calendar__cell flix-calendar__cell--selected" aria-selected="true">
              <button class="flix-calendar__btn" type="button" aria-label="11/9">11</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="12/9">12</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="13/9">13</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="14/9">14</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="15/9">15</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="16/9">16</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="17/9">17</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="18/9">18</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="19/9">19</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="20/9">20</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="21/9">21</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="22/9">22</button>
            </td></tr><tr><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="23/9">23</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="24/9">24</button>
            </td><td class="flix-calendar__cell">
              <button class="flix-calendar__btn" type="button" aria-label="25/9">25</button>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">26</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">27</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">28</span>
            </td><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">29</span>
            </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
              <span class="flix-calendar__btn flix-calendar__btn--disabled">30</span>
            </td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td></tr></tbody></table>
    </div>
  </div>
</div>

Birthday picker with input field

The birthday header renders one month at a time, and two select boxes with month and year selection.

Associating a calendar with an input field requires some attribute handling as well.

  1. When days are selected they update the value input field value. The days inputs must have aria-controls="{input_id}" to inform assistive technologies of this relationship.
  2. Since the input field value can be changed by external controls, it should have aria-live="polite" to allow screen readers to announce changes.
  3. You can group the input field and the calendar using the fieldset component.
  4. The margin between the input field and the calendar should be 3px, to achieve that, add --space-half modifier on the fieldset item that contains the calendar.
  5. Make sure to always match the calendar width with the input field, in case the input field is smaller than 276px, centralize the calendar relative to the input.
MoTuWeThFrSaSu
1 2 3 4
26 27 28
29 30
<div style="max-width:276px">
  <fieldset class="flix-fieldset">
    <div class="flix-fieldset__item">
      <div class="flix-input">
        <label class="flix-label flix-input__label" for="birthday-input">
          Birthday
        </label>
        <div class="flix-input__container">
          <input class="flix-input__field" id="birthday-input" type="text" aria-live="polite" value="10.1.1990"/>
        </div>
      </div>
    </div>
    <div class="flix-fieldset__item flix-fieldset__item--space-half">
      <div class="flix-calendar">
        <div class="flix-calendar__month">
          <div class="flix-calendar-header flix-calendar-header--birthday">
            <div class="flix-select flix-select--no-label flix-calendar-header__select">
              <select id="birthday-month" class="flix-select__field" aria-label="Select month" aria-controls="birthday-calendar">
                <option value="0" selected="">January</option>
                <option value="1">February</option>
                <option value="2">March</option>
                <option value="3">April</option>
                <option value="4">May</option>
                <option value="5">June</option>
                <option value="6">July</option>
                <option value="7">August</option>
                <option value="8">September</option>
                <option value="9">October</option>
                <option value="10">November</option>
                <option value="11">December</option>
              </select>
            </div>
            <div class="flix-select flix-select--no-label flix-calendar-header__select">
              <select id="birthday-year" class="flix-select__field" aria-label="Select year" aria-controls="birthday-calendar">
                <option value="1980">1980</option>
                <option value="1981">1981</option>
                <option value="1982">1982</option>
                <option value="1983">1983</option>
                <option value="1984">1984</option>
                <option value="1985">1985</option>
                <option value="1986">1986</option>
                <option value="1987">1987</option>
                <option value="1988">1988</option>
                <option value="1989">1989</option>
                <option value="1990" selected="">1990</option>
                <option value="1991">1991</option>
                <option value="1992">1992</option>
                <option value="1993">1993</option>
                <option value="1994">1994</option>
                <option value="1995">1995</option>
              </select>
            </div>
          </div>
          <table id="birthday-calendar" aria-live="polite" class="flix-calendar__table" role="grid"><thead><tr><th class="flix-calendar__cell" aria-label="Monday">Mo</th><th class="flix-calendar__cell" aria-label="Tuesday">Tu</th><th class="flix-calendar__cell" aria-label="Wednesday">We</th><th class="flix-calendar__cell" aria-label="Thursday">Th</th><th class="flix-calendar__cell" aria-label="Friday">Fr</th><th class="flix-calendar__cell" aria-label="Saturday">Sa</th><th class="flix-calendar__cell" aria-label="Sunday">Su</th></tr></thead><tbody><tr><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">1</span>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">2</span>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">3</span>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">4</span>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="5/9" aria-controls="birthday-input">5</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="6/9" aria-controls="birthday-input">6</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="7/9" aria-controls="birthday-input">7</button>
                </td></tr><tr><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="8/9" aria-controls="birthday-input">8</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="9/9" aria-controls="birthday-input">9</button>
                </td><td class="flix-calendar__cell flix-calendar__cell--selected" aria-selected="true">
                  <button class="flix-calendar__btn" type="button" aria-label="10/9" aria-controls="birthday-input">10</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="11/9" aria-controls="birthday-input">11</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="12/9" aria-controls="birthday-input">12</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="13/9" aria-controls="birthday-input">13</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="14/9" aria-controls="birthday-input">14</button>
                </td></tr><tr><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="15/9" aria-controls="birthday-input">15</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="16/9" aria-controls="birthday-input">16</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="17/9" aria-controls="birthday-input">17</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="18/9" aria-controls="birthday-input">18</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="19/9" aria-controls="birthday-input">19</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="20/9" aria-controls="birthday-input">20</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="21/9" aria-controls="birthday-input">21</button>
                </td></tr><tr><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="22/9" aria-controls="birthday-input">22</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="23/9" aria-controls="birthday-input">23</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="24/9" aria-controls="birthday-input">24</button>
                </td><td class="flix-calendar__cell">
                  <button class="flix-calendar__btn" type="button" aria-label="25/9" aria-controls="birthday-input">25</button>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">26</span>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">27</span>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">28</span>
                </td></tr><tr><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">29</span>
                </td><td class="flix-calendar__cell" aria-disabled="true">
                  <span class="flix-calendar__btn flix-calendar__btn--disabled">30</span>
                </td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td><td class="flix-calendar__cell" aria-disabled="true"></td></tr></tbody></table>
        </div>
      </div>
    </div>
  </fieldset>
</div>