March 2026

Su

Mo

Tu

We

Th

Fr

Sa

A few years ago I built a WordPress website for a company that rents out equipment. They wanted to allow their customers to rent equipment from their website, rather than having to call or stop in at the shop.

In order to add the booking functionality that integrates directly with their ERP I built a custom datepicker plugin using Svelte.

This post walks through building a basic datepicker built with Svelte.

Define the basic calendar grid

We start by defining a general grid for a calendar month and initializing the grid with let rows = initRows(). This initRows function just describes how many days are in a week, weeks in a month, etc. We'll fill this out with data for the selected month and year in a minute.

javascript

/**
 * Create the calendar grid
 * @returns {Array} rows
 */
function initRows() {
  return [
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
  ];
}

let rows = initRows();

Fill out the calendar grid for the selected month and year

Next we fill out the calendar grid with the correct dates using the components onMount lifecycle function.

javascript

/**
 * Return an array of days
 * @returns {Array} days
 */
export function arrDays() {
  return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
}

/**
 * Return a calendar month
 */
export function updateRows(month, year) {
  const rows = initRows();
  // pad the month with a zero if it's less than 10
  month = month.toString().padStart(2, "0");

  const firstDayOfCurrentMonth = format(
    startOfMonth(new Date(`${year}-${month}-01T12:00:00`)),
    "EEEEEE"
  );

  const lastDayOfCurrentMonth = +format(
    endOfMonth(new Date(`${year}-${month}-01T12:00:00`)),
    "d"
  );

  let row = 0;
  let col = 0;
  let start = false;
  let i = 0;

  // loop through each row (week)
  for (row = 0; row < 6; row++) {
    // loop through each day of the week and assign the date
    arrDays().forEach((daystr) => {
      if (i > lastDayOfCurrentMonth) {
        return;
      }

      if (!start && daystr === firstDayOfCurrentMonth) {
        i++;
        start = true;
      }

      rows[row][col] = i;
      col++;

      if (start) {
        i++;
      }
    })
    
    col = 0;
  }

  return rows;
}

/**
 * When the component mounts
 * update the rows array with data for current month and year
 */
onMount(() => {
  rows = updateRows(selectedMonth, selectedYear);
})

Updating the calendar grid

Now whenever we change the month and/or year we also need to update the calendar grid.

javascript

/**
 * Navigate months
 */
 function previousMonth() {
  selectedMonth--;

  if (selectedMonth <= 0) {
    selectedMonth = 12;
    selectedYear--;
  }

  // update the calendar grid for the newly selected month and year
  rows = updateRows(selectedMonth, selectedYear);
}

function nextMonth() {
  selectedMonth++;

  if (selectedMonth > 12) {
    selectedMonth = 1;
    selectedYear++;
  }

  // update the calendar grid for the newly selected month and year
  rows = updateRows(selectedMonth, selectedYear);
}

Displaying the calendar

Now that we have an array of days for the selected month and year we can display them in the calendar.

svelte

<table class="w-full">
  <thead>
    <tr>
      <!-- display the day headers -->
      {#each arrDays() as day}
        <th>
          <div class="flex justify-center w-full">
            <p
              class="text-base font-medium text-center text-gray-700 dark:text-gray-300"
            >
              {day}
            </p>
          </div>
        </th>
      {/each}
    </tr>
  </thead>

  <tbody>
    <!-- loop through each week -->
    {#each rows as col}
      <tr>
        <!-- loop through days of the week -->
        {#each col as d}
          <td>
            {#if d}
              <div class="flex justify-center w-full px-1 py-1 cursor-pointer">
                <button
                  on:click={() => {
                    selectDate(selectedYear, selectedMonth, d);
                  }}
                  class="text-center text-white transition-colors duration-200 bg-purple-700 border-none w-14 h-14 hover:bg-purple-600"
                  class:active-day-button={differenceInDays(
                      new Date(`${selectedFullDate}`),
                      new Date(`${selectedYear}-${padNumber(selectedMonth)}-${padNumber(d)}T00:00:00`)
                    ) === 0}
                >
                  {d}
                </button>
              </div>
            {/if}
          </td>
        {/each}
      </tr>
    {/each}
  </tbody>
</table>

View the project

For a full look at how this basic datepicker was created you can check out the GitHub repo. Keep in mind this is only meant to be a starting point that you can build off so it is pretty basic, but it can be customized pretty extensively to meet your needs.

https://github.com/zpthree/svelte-datepicker