Danny 🎠 6 days ago
I LOVE THE NEW DESIGN SO MUCH AAAAAAAAAAH
nick 🀞 6 days ago
the new designs are finally here! still a few rough edges here and there, but we'll smooth them out. if you spot any bugs, tell us <3

Static Calendar

Written by Danny β€’ 09.06.2025

Requirements

patience

Please note: This calendar is not a script and has to be updated by hand.

For a dynamic version that stays up to date automatically, you can read nick's tutorial here.


This tutorial shows how to create a calendar with highlighted events to hover.

I'm going to use June 2025 as an example.

Tip: I like to use my phone to compare calendars, so I would know on which day it starts (i.e. 26 for the previous month). 😊


First, the HTML:

<table cellpadding="5" cellspacing="0" width="100%">
  <caption>
    <h1>JUNE 2025</h1>
  </caption>
  <thead>
    <tr>
      <th>Mo</th>
      <th>Tu</th>
      <th>We</th>
      <th>Th</th>
      <th>Fr</th>
      <th>Sa</th>
      <th>Su</th>
    </tr>
  </thead>
  <tbody>

    <!-- Current month days -->
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    
  </tbody>
</table>

<div id="tooltip" class="dfoverlib"></div>

These 7 td's are for each day in the week.

<tr>
  <td></td>
  <td></td>
  <td></td>
  <td></td>
  <td></td>
  <td></td>
  <td></td>
</tr>

Now you can edit the <td></td> differently:

class="grey" makes the number slightly transparent, as to show, that it's not part of the current month

<td class="grey">26</td>

data-day="number" is needed for the javascript to recognize todays date and highlight it

<td data-day="1">1</td>

data-tooltip="EVENT" contains the event that is shown in the hover (overlib)

<td class="tooltip-trigger" data-tooltip="1st day!" data-day="1">EMOJI/PIXEL</td>

Second, the CSS:

Grey'ish numbers for previous/next month's days, highlighting today's date, some styling:

.grey {
	opacity:0.5;
}

.today {
	background: #eee;
}

th {
	color:rgba(0,0,0,.5);
	background:rgba(0,0,0,.15);
	padding:3px 0;
	text-transform:uppercase;
	text-align:center;
	text-shadow:1px 1px 1px rgba(255,255,255,.5);
	font-size:9.5px;
}

td, tr, th {
	text-align: center;
    font-size: 9pt;
}

tr:nth-child(odd) {
	background:rgba(255,255,255,.3);
}

Overlib on hover for events:

.tooltip-trigger:hover {
	background: linear-gradient(to right, transparent 0%, rgba(255, 255, 255, 1) 50%, transparent 100%);
	cursor:default;
}

.dfoverlib {
	position: absolute;
	background: #333;
	color: #fff;
	padding: 6px 10px;
	border-radius: 5px;
	font-size: 14px;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.1s;
	white-space: nowrap;
	z-index: 1000;
}

Third, the Javascript:

Paste this right before the </body>-Tag. It highlights the current day and enables the overlib on hover for events.

<script>
  const tooltip = document.getElementById("tooltip");
  const triggers = document.querySelectorAll(".tooltip-trigger");

  triggers.forEach((trigger) => {
    trigger.addEventListener("mousemove", (e) => {
      tooltip.textContent = trigger.dataset.tooltip;
      tooltip.style.left = e.pageX + 10 + "px"; 
      tooltip.style.top = e.pageY + 10 + "px";
    });

    trigger.addEventListener("mouseenter", () => {
      tooltip.style.opacity = "1";
    });

    trigger.addEventListener("mouseleave", () => {
      tooltip.style.opacity = "0";
    });
  });

  const today = new Date();
  const currentDay = today.getDate();

  const todayCell = document.querySelector(`td[data-day="${currentDay}"]`);
  if (todayCell) {
    todayCell.classList.add("today");
  }
</script>

Fourth, the icons:

You can pixel your own a icons/download them somewhere else, or as I do it: Use Emojis. 😊 There's almost everything as an Emoji and I am just too lazy to pixel them all for myself. Maybe one day, but not today! πŸ˜‚


So the full example for the month June looks like this now:

In this example, we included days 26–31 from the previous month, all the current month's days, and days 1–6 from the next month to match a real calendar layout. As I mentioned earlier, I like to keep my phone with the calendar open nearby for reference while building the HTML. ☺️

<style>
  .grey {
    opacity: 0.5;
  }

  .today {
    background: #eee;
  }

  th {
    color: rgba(0, 0, 0, 0.5);
    background: rgba(0, 0, 0, 0.15);
    padding: 3px 0;
    text-transform: uppercase;
    text-align: center;
    text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.5);
    font-size: 9.5px;
  }
  
  td, tr, th {
    text-align: center;
    font-size: 9pt;
  }

  tr:nth-child(odd) {
    background: rgba(255, 255, 255, 0.3);
  }

  .tooltip-trigger:hover {
    background: linear-gradient(
      to right,
      transparent 0%,
      rgba(255, 255, 255, 1) 50%,
      transparent 100%
    );
    cursor: default;
  }

  .dfoverlib {
    position: absolute;
    background: #333;
    color: #fff;
    padding: 6px 10px;
    border-radius: 5px;
    font-size: 14px;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.1s;
    white-space: nowrap;
    z-index: 1000;
  }
</style>

<table cellpadding="5" cellspacing="0" width="100%">
  <caption>
    <h1>JUNE 2025</h1>
  </caption>
  <thead>
    <tr>
      <th>Mo</th>
      <th>Tu</th>
      <th>We</th>
      <th>Th</th>
      <th>Fr</th>
      <th>Sa</th>
      <th>Su</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <!-- Previous month days (greyed out) -->
      <td class="grey">26</td>
      <td class="grey">27</td>
      <td class="grey">28</td>
      <td class="grey">29</td>
      <td class="grey">30</td>
      <td class="grey">31</td>
      
      <!-- Current month days -->
      <td class="tooltip-trigger" data-tooltip="dinner with friends" data-day="1">🍜</td>
    </tr>

    <tr>
      <td data-day="2">2</td>
      <td data-day="3">3</td>
      <td data-day="4">4</td>
      <td class="tooltip-trigger" data-tooltip="watching Final Destination 6" data-day="5">🍿</td>
      <td data-day="6">6</td>
      <td data-day="7">7</td>
      <td data-day="8">8</td>
    </tr>

    <tr>
      <td data-day="9">9</td>
      <td data-day="10">10</td>
      <td data-day="11">11</td>
      <td data-day="12">12</td>
      <td data-day="13">13</td>
      <td class="tooltip-trigger" data-tooltip="game night with friends">🎲</td>
      <td class="tooltip-trigger" data-tooltip="supporting my friends at a tennis match" data-day="14">🎾</td>
    </tr>

    <tr>
      <td data-day="16">16</td>
      <td data-day="17">17</td>
      <td data-day="18">18</td>
      <td data-day="19">19</td>
      <td class="tooltip-trigger" data-tooltip="HURRICANE FESTIVAL" data-day="20">🍻</td>
      <td class="tooltip-trigger" data-tooltip="HURRICANE FESTIVAL" data-day="21">🍻</td>
      <td class="tooltip-trigger" data-tooltip="HURRICANE FESTIVAL" data-day="22">🍻</td>
    </tr>

    <tr>
      <td data-day="23">23</td>
      <td data-day="24">24</td>
      <td data-day="25">25</td>
      <td data-day="26">26</td>
      <td data-day="27">27</td>
      <td class="tooltip-trigger" data-tooltip="mum's +1 at a party" data-day="28">πŸͺ©</td>
      <td data-day="29">29</td>
    </tr>

    <tr>
      <td data-day="30">30</td>
      
      <!-- Next month days (greyed out) -->
      <td class="grey">1</td>
      <td class="grey">2</td>
      <td class="grey">3</td>
      <td class="grey">4</td>
      <td class="grey">5</td>
      <td class="grey">6</td>
    </tr>
  </tbody>
</table>

<div id="tooltip" class="dfoverlib"></div>

<script>
  const tooltip = document.getElementById("tooltip");
  const triggers = document.querySelectorAll(".tooltip-trigger");

  triggers.forEach((trigger) => {
    trigger.addEventListener("mousemove", (e) => {
      tooltip.textContent = trigger.dataset.tooltip;
      tooltip.style.left = e.pageX + 10 + "px"; 
      tooltip.style.top = e.pageY + 10 + "px";
    });

    trigger.addEventListener("mouseenter", () => {
      tooltip.style.opacity = "1";
    });

    trigger.addEventListener("mouseleave", () => {
      tooltip.style.opacity = "0";
    });
  });

  const today = new Date();
  const currentDay = today.getDate();

  const todayCell = document.querySelector(`td[data-day="${currentDay}"]`);
  if (todayCell) {
    todayCell.classList.add("today");
  }
</script>