Uncategorized

Create a calendar plugin with vanilla Javascript

Moving away from all the frameworks and libraries

Introduction

When we hear about Javascript, we often hear about libraries and frameworks. There are about five gazillion choices today on how to use Javascript. Yet, we often forget that we can still use good old classic Javascript, without frameworks or libraries. In this article, we’ll build a plugin using nothing but vanilla Javascript. This plugin, quite simple, will allow us to include a calendar in an HTML page.

Setting up

We need three files, one HTML file, one CSS file and one Javascript file. Let’s start with our Javascript file, because this will be where we have the most work to do.

Plugin Skeleton

(function (root, factory) {
  root.myCalendar = factory(root);
})(this, (root) => {
  let privateVar = "No, No, No...";
  let init = () => {
    console.log("Init the calendar");
  };
  return {
    init,
  };
});

The first thing we need to do is to make our plugin available for our environment. We do this by using an IIFE (Immediately Invoked Function Expression). As you can see, we wrap our first function into parentheses, turning it into an expression that we call right away.

IIFE are useful to encapsulate code. My plugin’s code won’t be accessible from outside the plugin. But we’ll see that later.

Let’s break the code above a little bit:

In the main body of our function we do:

root.myCalendar = factory(root);

What is root? This is the first parameter of our IIFE, this. So, in a browser, this is the window object. We set window.myCalendar to factory(root)factory, the second parameter of our IIFE, is a function. This is, in fact, our plugin content.

The beauty of this approach is that window.myCalendar will only contain whatever my function returns. So, I’ll be able to call window.myCalendar.init(), but window.myCalendar.privateVar will be undefined, because it’s not returned by our IIFE.

Importing in our index.html

We already have a plugin! It doesn’t do much, but it works. Let’s create a HTML file and test it out.

<html>
  <head>
    <script src="simple-calendar.js"></script>
    <script>
      window.onload = function () {
        myCalendar.init();
        console.log(myCalendar.privateVar);
      };
    </script>
  </head>
  <body></body>
</html>

We load our Javascript file. I called it simple-calendar.js but name it whatever you wish. Then, after the window is done loading, inside the onload event listener, I’m called myCalendar.init() and console.log the myCalendar.privateVar variable.

Note: window.myCalendar and myCalendar is the same here 😉

So, here’s what I see in my console:

Console private variables

Great! The init function prints what we expected and privateVar is indeed undefined because it is not returned from our IIFE, so our plugin doesn’t know what you are talking about!

The CSS

Let’s get that out of the way, because this is not the point of the article. Create a CSS file and put the following styles inside it:

#calendar {
  background: #fff;
  border-radius: 4px;
  color: #222629;
  overflow: hidden;
  margin-top: 20px;
  max-width: 400px;
}

#calendar.hidden {
  display: none;
}

button {
  border: none;
}

#calendar .header {
  background: #ddd;
  height: 40px;
  line-height: 40px;
  text-align: center;
}

#calendar .header + div {
  border: 1px solid black;
}

#calendar .month {
  display: inline-block;
  font-weight: bold;
}

#calendar button {
  background: none;
  color: inherit;
  cursor: pointer;
  font-size: 23px;
  font-weight: bold;
  height: 100%;
  padding: 0 15px;
}

#calendar button:first-child {
  float: left;
}

#calendar button:last-child {
  float: right;
}

#calendar .cell {
  background: #fff;
  color: #5d5d5d;
  box-sizing: border-box;
  display: inline-block;
  padding: 10px 0;
  text-align: center;
  width: calc(100% / 7);
  cursor: pointer;
}

#calendar .cell:hover {
  color: white;
  background-color: blue;
}

#calendar .day {
  font-size: 0.8rem;
  padding: 8px 0;
}

#calendar .cell.today {
  background-color: blue;
  color: white;
}

#calendar .day {
  color: black;
}

Don’t forget to import it in our HTML file. In the <head> of our page, add the following line:

<link rel="stylesheet" href="calendar.css" />

Of course, replace the calendar.css with the name of your file.

Adding functionality

Ok, it’s very cute, but my plugin still doesn’t do anything here… Let’s begin.

Months, Days and Today

I’ll first need to get the months list, days list and today’s date. I want my calendar to focus on today’s date by default. So, in our plugin, above the private variable, let’s add those:

// Beginning of the file cut for brevity
    let monthList = new Array(
      "january",
      "february",
      "march",
      "april",
      "may",
      "june",
      "july",
      "august",
      "september",
      "october",
      "november",
      "december"
    );
    let dayList = new Array(
      "sunday",
      "monday",
      "tuesday",
      "wednesday",
      "thursday",
      "friday",
      "saturday"
    );
    let today = new Date();
    today.setHours(0, 0, 0, 0);
    let privateVar = "No, No, No...";

  let init = () => {
    console.log("Init the calendar");
  };
  return {
    init,
  };
});

Good, everything is setup. Now, we can start to modify the DOM to implement our calendar. Obviously, this step needs to be done inside the init function. We want the calendar to appear when we initialize our plugin.

There are a few things we need to do:

  • Create a header with the name of the current month and the current year. This header will also have next and previous buttons to navigate between months.
  • Below the header, we will have the list of days, from Sunday to Monday.
  • Finally, we will have the days in the current month.

The header

// Our variables are up there
let init = () => {
  let element = document.getElementById("calendar");

  let currentMonth = new Date(today.getFullYear(), today.getMonth(), 1);

  // Creating the div for our calendar's header
  let header = document.createElement("div");
  header.classList.add("header");
  element.appendChild(header);

  // Our "previous" button
  let previousButton = document.createElement("button");
  previousButton.setAttribute("data-action", "-1");
  previousButton.textContent = "\u003c";
  header.appendChild(previousButton);

  // Creating the div that will contain the actual month/year
  let monthDiv = document.createElement("div");
  monthDiv.classList.add("month");
  header.appendChild(monthDiv);

  // Our "next" button
  let nextButton = document.createElement("button");
  nextButton.setAttribute("data-action", "1");
  nextButton.textContent = "\u003e";
  header.appendChild(nextButton);
};

We have here just a few elements added with Javascript. We don’t use anything fancy, just the classic Javascript API with createElementappendChild and setAttribute. We created our div element for our header, that will contain the current’s month name. We also created our previous and next buttons.

Notice this line:

let element = document.getElementById("calendar");

This element is what will contain our calendar. We put it inside an element with the id calendar. This is a choice I made, but we’ll make it customizable later. But that means we need to add an element with the proper id in our HTML:

<!-- The <head> tag is up there-->
<body>
  <div id="calendar"></div>
</body>

That’s it for the HTML. And sure enough, we can see the header in our page.