Skip to content

ExpressiveCSS

Browse documentation

Calendar

A month of days with their events, on a table the page renders.

View as Markdown

A table.calendar shows a month, week or day of events. A .calendar-year lays out twelve months.

Your page renders the table. It has a <caption> naming the month, a header row of weekdays, then a row per week. Each day starts with a <time> and may hold a .calendar-events list of links or text.

Mark days from other months with outside and today with aria-current="date". The page owns the dates, the navigation between months and the events. CSS draws the grid. Long event titles ellipsize, and on a phone the days get shorter. To pick a date for a field, use the date picker.

October 2026
SunMonTueWedThuFriSat
<table class="calendar">
  <caption>October 2026</caption>
  <thead>
    <tr>
      <th scope="col"><abbr title="Sunday">Sun</abbr></th>
      <th scope="col"><abbr title="Monday">Mon</abbr></th>
      …
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="outside"><time datetime="2026-09-27">27</time></td>
      …
      <td aria-current="date">
        <time datetime="2026-10-15">15</time>
        <ul class="calendar-events">
          <li><a href="/events/standup">Standup</a></li>
        </ul>
      </td>
    </tr>
  </tbody>
</table>

Week and day views

Add week for an hourly grid. The header row starts with an empty <td> over the hour column, then one <th scope="col"> per day with its weekday and a <time>. Mark today's header with aria-current="date". Each body row is an hour, named by a <th scope="row">.

Put an event in the cell for its day and starting hour. It covers one hour unless you set --md-comp-calendar-event-duration in hours. --md-comp-calendar-event-start moves it down within the hour, so 0.5 starts it at half past.

The placement is only visual. A screen reader hears the hour row and the title, so write the event's time in a .visually-hidden span before its title. Events that overlap in time also overlap on screen, and an event that runs past the last hour row spills out of the table. Split overlapping events in the page and end long ones at the last row.

October 11 to 17, 2026
Sun Mon Tue Wed Thu Fri Sat
  • 9 AM to 9:30 AM, Standup
  • 9 AM to 9:30 AM, Standup
  • 10 AM to 11:30 AM, Design review
  • 11 AM to 12 PM, Interview
  • 12 PM to 1 PM, Lunch with the team
  • 2:30 PM to 4:30 PM, Planning
<table class="calendar week">
  <caption>October 11 to 17, 2026</caption>
  <thead>
    <tr>
      <td></td>
      <th scope="col"><abbr title="Sunday">Sun</abbr> <time datetime="2026-10-11">11</time></th>
      …
      <th scope="col" aria-current="date">
        <abbr title="Thursday">Thu</abbr> <time datetime="2026-10-15">15</time>
      </th>
      …
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row"><time datetime="14:00">2 PM</time></th>
      <td></td>
      …
      <td>
        <ul class="calendar-events">
          <li style="--md-comp-calendar-event-start: 0.5; --md-comp-calendar-event-duration: 2">
            <a href="/events/planning"><span class="visually-hidden">2:30 to 4:30 PM, </span>Planning</a>
          </li>
        </ul>
      </td>
      …
    </tr>
  </tbody>
</table>

A day calendar is the same grid with one day column.

Thursday, October 15, 2026
Thu
  • 9 AM to 9:30 AM, Standup
  • 12 PM to 1 PM, Lunch with the team
  • 2:30 PM to 4:30 PM, Planning
<table class="calendar day">
  <caption>Thursday, October 15, 2026</caption>
  <thead>
    <tr>
      <td></td>
      <th scope="col" aria-current="date">
        <abbr title="Thursday">Thu</abbr> <time datetime="2026-10-15">15</time>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row"><time datetime="09:00">9 AM</time></th>
      <td>
        <ul class="calendar-events">
          <li style="--md-comp-calendar-event-duration: 0.5">
            <span class="visually-hidden">9 to 9:30 AM, </span>Standup
          </li>
        </ul>
      </td>
    </tr>
    …
  </tbody>
</table>

Year view

Wrap twelve month tables in a .calendar-year to show a year. The months shrink and fill as many columns as fit. Render only the days. Event lists belong in the month, week or day view.

January 2026
SMTWTFS
February 2026
SMTWTFS
March 2026
SMTWTFS
April 2026
SMTWTFS
May 2026
SMTWTFS
June 2026
SMTWTFS
July 2026
SMTWTFS
August 2026
SMTWTFS
September 2026
SMTWTFS
October 2026
SMTWTFS
November 2026
SMTWTFS
December 2026
SMTWTFS
<div class="calendar-year">
  <table class="calendar">
    <caption>January 2026</caption>
    <thead>
      <tr><th scope="col"><abbr title="Sunday">S</abbr></th>…</tr>
    </thead>
    <tbody>
      <tr>
        <td class="outside"><time datetime="2025-12-28">28</time></td>
        …
      </tr>
    </tbody>
  </table>
  <table class="calendar">
    <caption>February 2026</caption>
    …
  </table>
  …
</div>

Tokens

Token Default
--md-comp-calendar-day-min-height 96px (Compact: 64px)
--md-comp-calendar-hour-height 48px (week and day)
--md-comp-calendar-outline-color --md-sys-color-outline-variant
--md-comp-calendar-event-container-color --md-sys-color-primary-container
--md-comp-calendar-event-color --md-sys-color-on-primary-container

No matching pages

  • Source color

    The seed every generated ramp derives from. Pick one and browse the docs — the whole theme follows. Error does not: it is a fixed hue.

    Default source: Mist Iris.

    ExpressiveCSS presets: Lagoon, Harbor, Breeze, Cobalt, Iris.

    Bold

    Soft

    Mist

    Glow