Skip to content

Instantly share code, notes, and snippets.

@anish000kumar
Created June 3, 2021 07:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anish000kumar/0e0d633f107f41dd7f146ba85c382b3f to your computer and use it in GitHub Desktop.
Save anish000kumar/0e0d633f107f41dd7f146ba85c382b3f to your computer and use it in GitHub Desktop.
Calendar component in pure JS
class Calendar {
constructor(selector){
this.MONTHS= ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
this.root = document.querySelector(selector);
this.activeDateTime = new Date();
this.render();
this.attachEvents();
}
get activeYear(){
return this.activeDateTime.getFullYear();
}
get activeMonth(){
return this.activeDateTime.getMonth();
}
get activeDate(){
return this.activeDateTime.getDate();
}
attachEvents(){
this.root.addEventListener('click', (e)=>{
if(e.target.dataset.control === 'cell'){
const dateValue = e.target.dataset.date;
alert(dateValue)
}
else if(e.target.dataset.control === 'next'){
this.getNextMonth()
}
else if(e.target.dataset.control === 'prev'){
this.getPrevMonth()
}
})
}
get monthDays(){
const date = new Date(this.activeYear, this.activeMonth+1, 0);
const padLeft = new Date(this.activeYear, this.activeMonth, 1).getDay();
const dates = Array.from(Array(date.getDate()), (_, index) => index+1);
for(let padding = 0; padding < padLeft; padding++){
dates.unshift(undefined);
}
return dates;
}
getNextMonth(){
this.activeDateTime.setMonth(this.activeMonth + 1);
this.render()
}
getPrevMonth(){
this.activeDateTime.setMonth(this.activeMonth - 1);
this.render()
}
getDayClass(day){
let className = "cell"
if(day === undefined)
className += " empty"
return className;
}
render(){
this.root.innerHTML = `
<div class="calendar" aria-label="calendar" aria-live="polite">
<div class="header">
<span data-control="prev" id="prev" role="button" class="prev">&lt;</span>
<div aria-label="month" class="active-month">${this.MONTHS[this.activeMonth]}</div>
<div aria-label="year" class="active-year">${this.activeYear}</div>
<div data-control="next" id="next" role="button" class="next">&gt;</div>
</div>
<div class="body">
<div class="row days">
<div role="cell" class="cell">S</div>
<div role="cell" class="cell">M</div>
<div role="cell" class="cell">T</div>
<div role="cell" class="cell">W</div>
<div role="cell" class="cell">T</div>
<div role="cell" class="cell">F</div>
<div role="cell" class="cell">S</div>
</div>
<div role="row" class="row">
${this.monthDays.map(date => (`<div data-control="cell" data-date=${date} role="cell" class="${this.getDayClass(date)}">${date ? date: ''}</div>`)).join("")}
</div>
</div>
</div>
`;
}
}
// USAGE:
const cal = new Calendar("#main");
@anish000kumar
Copy link
Author

CSS:

.calendar {
  
  background: #fff;
  width: 300px;
  font-family: sans-serif;
  padding: 10px;
  border-radius: 5px;
  box-shadow: 0 5px 20px 0 rgba(0,0,0,0.05);
}

.calendar .header {
  display: flex;
  justify-content: space-between;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
  margin-bottom: 10px;
  
}

#next, #prev {
  cursor: pointer;
}

.calendar .row {
  display: flex;
  flex-wrap: wrap;
}

.row.days {
  background: rgba(0,0,0,0.05);
  border-radius: 5px;
}

.calendar .row .cell {
  text-align:center;
  width: calc(300px / 7);
  height: calc(300px / 7);
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
}

.calendar .row .cell:hover {
  background: #eee;
}

.empty {
  pointer-events: none;
}



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment