Simple Javascript Calendar With Events (Free Code Download)

Welcome to a tutorial on how to create a simple pure Javascript Calendar. Are you looking to develop a calendar web app, without using any server-side scripts? Be it for a commercial project, school project, or just curiosity – You have come to the correct place. This guide will walk you through how to create a pure Javascript calendar, all made possible with local storage. Read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

TABLE OF CONTENTS

Download & Demo How It Works Useful Bits & Links
The End

 

 

DOWNLOAD & DEMO

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • If you want to set the calendar to start the week on Monday instead, set cal.sMon = true in calendar.js.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

JAVASCRIPT CALENDAR DEMO

 

 

HOW THE CALENDAR WORKS

All right, let us now get into a little more details on how the calendar works. Not going to explain line-by-line, but here’s a quick walk-through.

 

PART 1) CALENDAR HTML

calendar.html
<div id="cal-wrap">
  <!-- (A) PERIOD SELECTOR -->
  <div id="cal-date">
    <select id="cal-mth"></select>
    <select id="cal-yr"></select>
  </div>

  <!-- (B) CALENDAR -->
  <div id="cal-container"></div>

  <!-- (C) EVENT FORM -->
  <form id="cal-event">
    <h1 id="evt-head"></h1>
    <div id="evt-date"></div>
    <textarea id="evt-details" required></textarea>
    <input id="evt-close" type="button" value="Close"/>
    <input id="evt-del" type="button" value="Delete"/>
    <input id="evt-save" type="submit" value="Save"/>
  </form>
</div>

The HTML should be straightforward enough, there are only 3 sections here:

  • <div id="cal-date"> The month and year selector.
  • <div id="cal-container"> Where we will display the calendar for the selected month and year.
  • <form id="cal-event"> A form to add/edit the calendar events.

 

 

PART 2) CALENDAR INITIALIZE

calendar.js
var cal = {
  // (A) PROPERTIES
  // (A1) COMMON CALENDAR
  sMon : false, // Week start on Monday?
  mName : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // Month Names
 
  // (A2) CALENDAR DATA
  data : null, // Events for the selected period
  sDay : 0, sMth : 0, sYear : 0, // Current selected day, month, year
 
  // (A3) COMMON HTML ELEMENTS
  hMth : null, hYear : null, // month/year selector
  hForm : null, hfHead : null, hfDate : null, hfTxt : null, hfDel : null, // event form
 
  // (B) INIT CALENDAR
  init : () => {
    // (B1) GET + SET COMMON HTML ELEMENTS
    cal.hMth = document.getElementById("cal-mth");
    cal.hYear = document.getElementById("cal-yr");
    cal.hForm = document.getElementById("cal-event");
    cal.hfHead = document.getElementById("evt-head");
    cal.hfDate = document.getElementById("evt-date");
    cal.hfTxt = document.getElementById("evt-details");
    cal.hfDel = document.getElementById("evt-del");
    document.getElementById("evt-close").onclick = cal.close;
    cal.hfDel.onclick = cal.del;
    cal.hForm.onsubmit = cal.save;
 
    // (B2) DATE NOW
    let now = new Date(),
        nowMth = now.getMonth(),
        nowYear = parseInt(now.getFullYear());
 
    // (B3) APPEND MONTHS SELECTOR
    for (let i=0; i<12; i++) {
      let opt = document.createElement("option");
      opt.value = i;
      opt.innerHTML = cal.mName[i];
      if (i==nowMth) { opt.selected = true; }
      cal.hMth.appendChild(opt);
    }
    cal.hMth.onchange = cal.list;
 
    // (B4) APPEND YEARS SELECTOR
    // Set to 10 years range. Change this as you like.
    for (let i=nowYear-10; i<=nowYear+10; i++) {
      let opt = document.createElement("option");
      opt.value = i;
      opt.innerHTML = i;
      if (i==nowYear) { opt.selected = true; }
      cal.hYear.appendChild(opt);
    }
    cal.hYear.onchange = cal.list;
 
    // (B5) START - DRAW CALENDAR
    cal.list();
};
window.addEventListener("load", cal.init);

cal.init() is the first thing that runs on page load to initialize the calendar. It looks complicated at first, but keep calm and look carefully – All it does is to set up the HTML interface:

  • Add months to the selector.
  • Add years to the selector.
  • Attach the add/edit event form click and submit handlers.

That’s all.

 

 

PART 3) DRAW CALENDAR

calendar.js
// (C) DRAW CALENDAR FOR SELECTED MONTH
list : () => {
  // (C1) BASIC CALCULATIONS - DAYS IN MONTH, START + END DAY
  // Note - Jan is 0 & Dec is 11
  // Note - Sun is 0 & Sat is 6
  cal.sMth = parseInt(cal.hMth.value); // selected month
  cal.sYear = parseInt(cal.hYear.value); // selected year
  let daysInMth = new Date(cal.sYear, cal.sMth+1, 0).getDate(), // number of days in selected month
      startDay = new Date(cal.sYear, cal.sMth, 1).getDay(), // first day of the month
      endDay = new Date(cal.sYear, cal.sMth, daysInMth).getDay(), // last day of the month
      now = new Date(), // current date
      nowMth = now.getMonth(), // current month
      nowYear = parseInt(now.getFullYear()), // current year
      nowDay = cal.sMth==nowMth && cal.sYear==nowYear ? now.getDate() : null ;
 
  // (C2) LOAD DATA FROM LOCALSTORAGE
  cal.data = localStorage.getItem("cal-" + cal.sMth + "-" + cal.sYear);
  if (cal.data==null) {
  localStorage.setItem("cal-" + cal.sMth + "-" + cal.sYear, "{}");
  cal.data = {};
  } else { cal.data = JSON.parse(cal.data); }
 
  // (C3) DRAWING CALCULATIONS
  // Blank squares before start of month
  let squares = [];
  if (cal.sMon && startDay != 1) {
    let blanks = startDay==0 ? 7 : startDay ;
    for (let i=1; i<blanks; i++) { squares.push("b"); }
  }
  if (!cal.sMon && startDay != 0) {
    for (let i=0; i<startDay; i++) { squares.push("b"); }
  }
 
  // Days of the month
  for (let i=1; i<=daysInMth; i++) { squares.push(i); }
 
  // Blank squares after end of month
  if (cal.sMon && endDay != 0) {
    let blanks = endDay==6 ? 1 : 7-endDay;
    for (let i=0; i<blanks; i++) { squares.push("b"); }
  }
  if (!cal.sMon && endDay != 6) {
    let blanks = endDay==0 ? 6 : 6-endDay;
    for (let i=0; i<blanks; i++) { squares.push("b"); }
  }
 
  // (C4) DRAW HTML CALENDAR
  // Get container
  let container = document.getElementById("cal-container"),
      cTable = document.createElement("table");
  cTable.id = "calendar";
  container.innerHTML = "";
  container.appendChild(cTable);

  // First row - Day names
  let cRow = document.createElement("tr"),
      days = ["Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
  if (cal.sMon) { days.push(days.shift()); }
  for (let d of days) {
    let cCell = document.createElement("td");
    cCell.innerHTML = d;
    cRow.appendChild(cCell);
  }
  cRow.classList.add("head");
  cTable.appendChild(cRow);

  // Days in Month
  let total = squares.length;
  cRow = document.createElement("tr");
  cRow.classList.add("day");
  for (let i=0; i<total; i++) {
    let cCell = document.createElement("td");
    if (squares[i]=="b") { cCell.classList.add("blank"); }
    else {
      if (nowDay==squares[i]) { cCell.classList.add("today"); }
      cCell.innerHTML = `<div class="dd">${squares[i]}</div>`;
      if (cal.data[squares[i]]) {
        cCell.innerHTML += "<div class='evt'>" + cal.data[squares[i]] + "</div>";
      }
      cCell.onclick = () => { cal.show(cCell); };
    }
    cRow.appendChild(cCell);
    if (i!=0 && (i+1)%7==0) {
      cTable.appendChild(cRow);
      cRow = document.createElement("tr");
      cRow.classList.add("day");
    }
  }
 
  // (C5) REMOVE ANY PREVIOUS ADD/EDIT EVENT DOCKET
  cal.close();
}

cal.list() draws the calendar for the currently selected month/year, and it is the most complicated function in this project. Long story short:

  • (C1 & C2) The events data is kept in the localStorage in a monthly manner (cal-MONTH-YEAR = JSON ENCODED OBJECT).
  • (C1 & C2) Retrieve the events data for the selected month/year, and put it into cal.data.
  • (C3) Do all the calculations in squares = [] first.
  • (C4) Then, loop through squares to draw the HTML calendar.

 

 

PART 4) SHOW/EDIT CALENDAR EVENT

calendar.js
// (D) SHOW EDIT EVENT DOCKET FOR SELECTED DAY
show : (el) => {
  // (D1) FETCH EXISTING DATA
  cal.sDay = el.getElementsByClassName("dd")[0].innerHTML;
  let isEdit = cal.data[cal.sDay] !== undefined ;

  // (D2) UPDATE EVENT FORM
  cal.hfTxt.value = isEdit ? cal.data[cal.sDay] : "" ;
  cal.hfHead.innerHTML = isEdit ? "EDIT EVENT" : "ADD EVENT" ;
  cal.hfDate.innerHTML = `${cal.sDay} ${cal.mName[cal.sMth]} ${cal.sYear}`;
  if (isEdit) { cal.hfDel.classList.remove("ninja"); }
  else { cal.hfDel.classList.add("ninja"); }
  cal.hForm.classList.remove("ninja");
},

// (E) CLOSE EVENT DOCKET
close : () => {
  cal.hForm.classList.add("ninja");
}

When the user clicks on a date cell, cal.show() will be called. Pretty self-explanatory – We fetch the event from cal.data, then show the add/edit event form.

 

PART 5) SAVE/DELETE EVENTS DATA

calendar.js
// (F) SAVE EVENT
save : () => {
  cal.data[cal.sDay] = cal.hfTxt.value;
  localStorage.setItem(`cal-${cal.sMth}-${cal.sYear}`, JSON.stringify(cal.data));
  cal.list();
  return false;
},

// (G) DELETE EVENT FOR SELECTED DATE
del : () => { if (confirm("Delete event?")) {
  delete cal.data[cal.sDay];
  localStorage.setItem(`cal-${cal.sMth}-${cal.sYear}`, JSON.stringify(cal.data));
  cal.list();
}

Lastly, these are self-explanatory functions again – We simply update the events data in localStorage.

 

 

USEFUL BITS & LINKS

Finally, here are a few more extras that may be useful.

 

MULTIPLE EVENTS PER DAY?

Of course, we can. Let’s take a look at the current save() function:

cal.data[cal.sDay] = cal.hfTxt.value;

We are pretty much storing the event data in data[DAY] = EVENT now. So to allow multiple events on the same day, the general idea is to change the current structure into a multi-dimensional array data[DAY] = [EVENT, EVENT, EVENT].

cal.data[cal.sDay] = [];
cal.data[cal.sDay].push(document.getElementById("evt-details").value);

Then, here comes the big problem. We have to redo all the rest of the functions to properly draw multiple events and manage them. As you can guess, that will increase the complexity exponentially, turning this into a “not simple tutorial”.

This is why I don’t answer the “support multiple events” and “span an event across multiple days” questions – Feel free to challenge yourself though, this simple calendar is a good starting point.

 

LIMITATIONS

  • Only one event is allowed in a day.
  • The events cannot span across multiple days.
  • The Javascript calendar requires the use of local storage. If it is disabled on the browser or not supported, then it will not be able to save the events at all.

But of course, I have released this as an open-source. So feel free to tweak it however you see fit.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

13 thoughts on “Simple Javascript Calendar With Events (Free Code Download)”

  1. I need help with a simple event calendar . I dont have any skills at all. Most of the wordpress widgets are too huge and slow my website.

  2. Would it be possible to have the current date cell be colored in a different color? I am trying to do it myself but my javascript skills are very basic. Thanks.

  3. Hi, thanks for sharing your work, I find it useful.
    Regarding multiple events, in my case all I did was something like:

    1. This is an event <br>
    2. This is another event

    I dont need more than that.
    Thanks again

Leave a Comment

Your email address will not be published.