Key features include simple localization, CSS/HTML customization, multiple calendar instances on a single page, automatic theme switching (light and dark), customizable week starts and weekends, week number display, accessibility features (ARIA labels, tabindex, keyboard navigation), and date/time range selection with limits and custom popups.
The code is easy to understand and is a good starting point if you want to display events and schedules on the page.
1. Install and import the VanillaCalendar component.
# NPM $ npm i vanilla-calendar-pro
// JavaScript import Calendar from 'vanilla-calendar-pro'; // Core Stylesheet import 'vanilla-calendar-pro/styles/vanilla-calendar.min.css'; // Themes import 'vanilla-calendar-pro/styles/themes/dark.min.css'; import 'vanilla-calendar-pro/styles/themes/light.min.css';
2. Or load the JavaScript library directly in the document.
<link href="https://cdn.jsdelivr.net/npm/vanilla-calendar-pro/styles/index.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/vanilla-calendar-pro/index.js" defer></script>
3. Create a container in which you want to render the calendar
<div id="calendar"> </div>
4. Generate a basic calendar.
const calendar = new Calendar('#calendar');
// Browser usages
const { Calendar } = window.VanillaCalendarPro;
// initialize the calendar
calendar.init(); 5. Set the calendar type: ‘default’ | ‘multiple’ | ‘month’ | ‘year’.
const calendar = new Calendar('#calendar', {
type: 'multiple',
}); 6. Specify the number of months to display if the calendar type is defined as “multiple”. Default: 2.
const calendar = new Calendar('#calendar', {
displayMonthsCount: 2,
}); 7. Date configs.
const calendar = new Calendar('#calendar', {
dateToday: 'today',
dateMin: '1970-01-01',
dateMax: '2470-12-31',
}); 8. Set the language of the calendar.
const calendar = new Calendar('#calendar', {
locale: 'de-AT',
}); // OR
const calendar = new Calendar('#calendar', {
locale: {
months: {
short: ['Vör', 'Thors', 'Skadi', 'Freya', 'Baldur', 'Njord', 'Tyr', 'Frigg', 'Odin', 'Loki', 'Hel', 'Idunn'],
long: [
'Vörmánuðr',
'Thorsmánuðr',
'Skadimánuðr',
'Freymánuðr',
'Baldurmánuðr',
'Njordmánuðr',
'Tyrmánuðr',
'Friggmánuðr',
'Odinmánuðr',
'Lokimánuðr',
'Helmánuðr',
'Idunnmánuðr',
],
},
weekdays: {
short: ['Sunna', 'Mani', 'Tiw', 'Woden', 'Thor', 'Frigg', 'Saturn'],
long: ['Sunnandæg', 'Manadæg', 'Tiwesdæg', 'Wodensdæg', 'Thorsdæg', 'Friggsdæg', 'Saturnsdag'],
},
},
}); 9. Config the hover-triggered popup.
const calendar = new Calendar('#calendar', {
popups: {
'2022-06-28': {
modifier: 'bg-red',
html: 'Meeting at 9:00 PM',
},
}
}); 10. Change the default layout template.
// Default
new Calendar('#calendar', {
layouts: {
default: `
<div class="${self.styles.header}" data-vc="header" role="toolbar" aria-label="${self.labels.navigation}">
<#ArrowPrev [month] />
<div class="${self.styles.headerContent}" data-vc-header="content">
<#Month />
<#Year />
</div>
<#ArrowNext [month] />
</div>
<div class="${self.styles.wrapper}" data-vc="wrapper">
<#WeekNumbers />
<div class="${self.styles.content}" data-vc="content">
<#Week />
<#Dates />
<#DateRangeTooltip />
</div>
</div>
<#ControlTime />
`
}
}); // Multiple
new Calendar('#calendar', {
layouts: {
multiple: `
<div class="${self.styles.controls}" data-vc="controls" role="toolbar" aria-label="${self.labels.navigation}">
<#ArrowPrev [month] />
<#ArrowNext [month] />
</div>
<div class="${self.styles.grid}" data-vc="grid">
<#Multiple>
<div class="${self.styles.column}" data-vc="column" role="region">
<div class="${self.styles.header}" data-vc="header">
<div class="${self.styles.headerContent}" data-vc-header="content">
<#Month />
<#Year />
</div>
</div>
<div class="${self.styles.wrapper}" data-vc="wrapper">
<#WeekNumbers />
<div class="${self.styles.content}" data-vc="content">
<#Week />
<#Dates />
</div>
</div>
</div>
<#/Multiple>
<#DateRangeTooltip />
</div>
<#ControlTime />
`
}
}); // Month
new Calendar('#calendar', {
layouts: {
month: `
<div class="${self.styles.header}" data-vc="header" role="toolbar" aria-label="${self.labels.navigation}">
<div class="${self.styles.headerContent}" data-vc-header="content">
<#Month />
<#Year />
</div>
</div>
<div class="${self.styles.wrapper}" data-vc="wrapper">
<div class="${self.styles.content}" data-vc="content">
<#Months />
</div>
</div>
`
}
}); // Year
new Calendar('#calendar', {
layouts: {
year: `
<div class="${self.styles.header}" data-vc="header" role="toolbar" aria-label="${self.labels.navigation}">
<#ArrowPrev [year] />
<div class="${self.styles.headerContent}" data-vc-header="content">
<#Month />
<#Year />
</div>
<#ArrowNext [year] />
</div>
<div class="${self.styles.wrapper}" data-vc="wrapper">
<div class="${self.styles.content}" data-vc="content">
<#Years />
</div>
</div>
`
}
}); 11. Override the default CSS classes.
new Calendar('#calendar', {
styles: {
calendar: 'vc',
controls: 'vc-controls',
grid: 'vc-grid',
column: 'vc-column',
header: 'vc-header',
headerContent: 'vc-header__content',
month: 'vc-month',
year: 'vc-year',
arrowPrev: 'vc-arrow vc-arrow_prev',
arrowNext: 'vc-arrow vc-arrow_next',
wrapper: 'vc-wrapper',
content: 'vc-content',
months: 'vc-months',
monthsMonth: 'vc-months__month',
years: 'vc-years',
yearsYear: 'vc-years__year',
week: 'vc-week',
weekDay: 'vc-week__day',
weekNumbers: 'vc-week-numbers',
weekNumbersTitle: 'vc-week-numbers__title',
weekNumbersContent: 'vc-week-numbers__content',
weekNumber: 'vc-week-number',
dates: 'vc-dates',
date: 'vc-date',
dateBtn: 'vc-date__btn',
datePopup: 'vc-date__popup',
dateRangeTooltip: 'vc-date-range-tooltip',
time: 'vc-time',
timeContent: 'vc-time__content',
timeHour: 'vc-time__hour',
timeMinute: 'vc-time__minute',
timeKeeping: 'vc-time__keeping',
timeRanges: 'vc-time__ranges',
timeRange: 'vc-time__range',
},
}); 12. Override the default ARIA labels.
new Calendar('#calendar', {
labels: {
application: 'Calendar',
navigation: 'Calendar Navigation',
arrowNext: {
month: 'Next month',
year: 'Next list of years',
},
arrowPrev: {
month: 'Previous month',
year: 'Previous list of years',
},
month: 'Select month, current selected month:',
months: 'List of months',
year: 'Select year, current selected year:',
years: 'List of years',
week: 'Days of the week',
weekNumber: 'Numbers of weeks in a year',
dates: 'Dates in the current month',
selectingTime: 'Selecting a time ',
inputHour: 'Hours',
inputMinute: 'Minutes',
rangeHour: 'Slider for selecting hours',
rangeMinute: 'Slider for selecting minutes',
btnKeeping: 'Switch AM/PM, current position:',
},
}); 13. Callback functions.
new Calendar('#calendar', {
onClickDate!: (self: Calendar, event: MouseEvent) => void;
onClickWeekDay!: (self: Calendar, day: number, dateEls: HTMLElement[], event: MouseEvent) => void;
onClickWeekNumber!: (self: Calendar, number: number, year: number, dateEls: HTMLElement[], event: MouseEvent) => void;
onClickTitle!: (self: Calendar, event: MouseEvent) => void;
onClickMonth!: (self: Calendar, event: MouseEvent) => void;
onClickYear!: (self: Calendar, event: MouseEvent) => void;
onClickArrow!: (self: Calendar, event: MouseEvent) => void;
onChangeTime!: (self: Calendar, event: Event, isError: boolean) => void;
onChangeToInput!: (self: Calendar, event: Event) => void;
onCreateDateRangeTooltip!: (self: Calendar, dateEl: HTMLElement, tooltipEl: HTMLElement, dateElBCR: DOMRect, mainElBCR: DOMRect) => string;
onCreateDateEls!: (self: Calendar, dateEl: HTMLElement) => void;
onCreateMonthEls!: (self: Calendar, monthEl: HTMLElement) => void;
onCreateYearEls!: (self: Calendar, yearEl: HTMLElement) => void;
onInit!: (self: Calendar) => void;
onUpdate!: (self: Calendar) => void;
onDestroy!: (self: Calendar) => void;
onShow!: (self: Calendar) => void;
onHide!: (self: Calendar) => void;
}); 14. More configuration options.
inputMode: boolean = false; positionToInput: PositionToInput = 'left'; firstWeekday: WeekDayID = 1; monthsToSwitch: 1 | MonthsCount = 1; themeAttrDetect: string = 'html[data-theme]'; displayDateMin!: DateAny; displayDateMax!: DateAny; displayDatesOutside: boolean = true; displayDisabledDates: boolean = false; displayMonthsCount!: MonthsCount; disableDates: DatesArr = []; disableAllDates: boolean = false; disableDatesPast: boolean = false; disableDatesGaps: boolean = false; disableWeekdays: Range<7>[] = []; disableToday: boolean = false; enableDates: DatesArr = []; enableEdgeDatesOnly: boolean = true; enableDateToggle: ToggleSelected = true; enableWeekNumbers: boolean = false; enableMonthChangeOnDayClick: boolean = true; enableJumpToSelectedDate: boolean = false; // 'single' | 'multiple' | 'multiple-ranged' | false selectionDatesMode: false | DateMode = 'single'; selectionMonthsMode: boolean | 'only-arrows' = true; selectionYearsMode: boolean | 'only-arrows' = true; selectionTimeMode: false | 12 | 24 = false; selectedDates: DatesArr = []; selectedMonth!: Range<12>; selectedYear!: number; selectedHolidays: DatesArr = []; selectedWeekends: WeekDays<WeekDayID> = [0, 6]; selectedTime!: string; // string (custom theme) | 'light' | 'dark' | 'system' selectedTheme: ThemesDefault | string = 'system'; timeMinHour: Range<24> = 0; timeMaxHour: Range<24> = 23; timeMinMinute: Range<60> = 0; timeMaxMinute: Range<60> = 59; timeControls: TimeControl = 'all'; timeStepHour: number = 1; timeStepMinute: number = 1; sanitizerHTML: (dirtyHtml: string) => string = (dirtyHtml: string) => dirtyHtml;
15. API methods.
// update
calendar.update({
year: boolean;
month: boolean;
dates: boolean | 'only-first';
holidays: boolean;
time: boolean;
});
// set
calendar.set({
locale: 'de-AT',
firstWeekday: 0,
}, {
dates: true,
});
// show
calendar.show();
// hide
calendar.hide();
// destroy
calendar.destroy(); v3.0.5 (04/14/2025)
v3.0.4 (04/14/2025)
v3.0.3 (12/18/2024)
v3.0.2 (12/17/2024)
v3.0.1 (12/02/2024)
v2.9.10 (08/21/2024)
v2.9.9 (08/17/2024)
v2.9.8 (08/03/2024)
v2.9.7 (07/28/2024)
v2.9.6 (03/11/2024)
v2.9.5 (02/19/2024)
v2.9.4 (02/18/2024)
v2.9.3 (01/27/2024)
v2.9.2 (12/09/2023)
v2.9.1 (12/08/2023)
v2.9.0 (12/06/2023)
v2.8.5 (11/30/2023)
v2.8.4 (11/29/2023)
v2.8.3 (11/28/2023)
v2.7.2 (11/08/2023)
v2.7.1 (11/07/2023)
v2.7.0 (10/13/2023)
v2.6.8 (10/10/2023)
v2.6.7 (10/04/2023)
v2.6.6 (10/02/2023)
v2.6.5 (09/30/2023)
v2.6.4 (09/21/2023)
v2.6.3 (09/19/2023)
v2.6.2 (09/14/2023)
v2.6.1 (06/21/2023)
v2.6.0 (05/11/2023)
v2.5.9 (05/01/2023)
v2.5.8 (04/26/2023)
v2.5.7 (04/24/2023)
v2.5.6 (04/10/2023)
v2.5.4 (04/06/2023)
v2.5.3 (03/31/2023)
v2.5.2 (03/30/2023)
v2.5.1 (03/15/2023)
v2.5.0 (03/11/2023)
v2.4.0 (02/19/2023)
v2.3.0 (02/15/2023)
v2.2.8 (02/14/2023)
v2.2.7 (02/12/2023)
v2.2.5 (11/21/2022)
v2.2.4 (11/17/2022)
v2.2.3 (11/16/2022)
v2.2.1 (11/16/2022)
v2.2.0 (11/16/2022)
v2.1.7 (11/11/2022)
v2.1.6 (11/08/2022)
v2.1.5 (11/06/2022)
v2.1.3 (10/30/2022)
v2.1.1 (10/26/2022)
v2.1.0 (10/25/2022)
v2.0.0 (08/27/2022)
v1.5.5 (08/27/2022)
v1.4.9 (07/20/2022)
v1.4.8 (07/16/2022)
v1.4.7 (07/15/2022)
v1.4.6 (07/14/2022)
v1.4.5 (07/13/2022)
v1.4.3 (07/10/2022)
v1.4.0 (07/04/2022)
v1.3.5 (06/26/2022)
v1.3.4 (06/24/2022)
v1.3.2 (06/16/2022)
v1.3.1 (06/12/2022)
v1.2.8 (06/06/2022)
v1.2.6 (05/28/2022)
v1.2.4 (05/18/2022)
The post Simple Multilingual Calendar Component With Vanilla JavaScript appeared first on CSS Script.
Today's links Demand destruction vs fuel-superceding infrastructure: Will Trump hormuz us into the full Gretacene?…
AI has aced medical exams, but there’s a wide gap between tests and the real…
The most consequential cybersecurity development of 2026 is one that most tax and accounting firms…
Speed matters in M&A, but it rarely sets the pace on its own. Deal teams…
Today’s homebuyers are entering the market with more information at their fingertips than ever before, largely…
Look at the mainstream stories about artificial intelligence, and most of them focus on how…
This website uses cookies.