A lightweight, zero-dependency JavaScript calendar component
SimpleCalendarJs is a zero-dependency calendar component. Include the CSS and JS files in your project:
<link rel="stylesheet" href="simple-calendar-js.css" />
<script src="simple-calendar-js.js"></script>import SimpleCalendarJs from './simple-calendar-js.js';
import './simple-calendar-js.css';Note: Make sure to include the CSS file for proper styling.
Create a calendar instance by passing a container element and options:
// Create a container in your HTML
<div id="calendar"></div>
// Initialize the calendar
const calendar = new SimpleCalendarJs('#calendar', {
defaultView: 'month',
weekStartsOn: 1, // 0 = Sunday, 1 = Monday
locale: 'en-US',
use24Hour: false,
fetchEvents: async (start, end) => {
// Fetch events from your API
const response = await fetch(`/api/events?start=${start}&end=${end}`);
return response.json();
},
onEventClick: (event) => {
console.log('Event clicked:', event);
},
onSlotClick: (date) => {
console.log('Empty slot clicked:', date);
}
});All available options when creating a calendar instance:
| Option | Type | Default | Description |
|---|---|---|---|
defaultView | String | 'month' | Initial view: 'month', 'week', or 'day' |
defaultDate | Date | null | Initial date to display (defaults to today if not provided) |
weekStartsOn | Number | 0 | First day of week: 0 (Sunday) or 1 (Monday) |
locale | String | 'default' | Locale code (e.g., 'en-US', 'fr-FR', 'pt-PT'). Supports 34+ locales. |
weekdayFormat | String | 'short' | Weekday name format: 'narrow' (1-2 letters), 'short' (abbreviated), or 'long' (full name) |
use24Hour | Boolean | false | Use 24-hour time format instead of 12-hour with AM/PM |
showTimeInItems | Boolean | true | Show time in event items across all views |
showGridLines | Boolean | true | Show/hide grid lines (borders between cells and time slots) |
showBorder | Boolean | true | Show/hide calendar outer border |
maxEventsPerCell | Number | 3 | Maximum events per cell in month view before showing "+N more". Set to 0 for unlimited (show all events) |
Control which toolbar elements are visible:
| Option | Type | Default | Description |
|---|---|---|---|
showToolbar | Boolean | true | Show/hide the entire toolbar |
showTodayButton | Boolean | true | Show/hide the "Today" button |
showNavigation | Boolean | true | Show/hide navigation arrows (← →) |
showTitle | Boolean | true | Show/hide the month/week/day title |
showYearPicker | Boolean | true | Enable/disable year selection (clickable year) |
showViewSwitcher | Boolean | true | Show/hide Month/Week/Day view switcher buttons |
enabledViews | Array | ['month', 'week', 'day', 'list'] | Which views are available to switch to |
showTooltips | Boolean | true | Show/hide event tooltips on hover |
enableDragDrop | Boolean | false | Enable drag and drop to move events |
enableResize | Boolean | false | Enable resizing events to change duration |
monthTimedEventStyle | String | 'list' | Display style for timed events in month view: 'list' (schedule format) or 'block' (traditional blocks) |
Example: Start calendar on a specific date:
new SimpleCalendarJs('#calendar', {
defaultView: 'month',
defaultDate: new Date(2024, 5, 15) // June 15, 2024
});Example: Hide grid lines for a cleaner look:
new SimpleCalendarJs('#calendar', {
showGridLines: false
});Example: Hide toolbar and only allow month view:
new SimpleCalendarJs('#calendar', {
showToolbar: false,
enabledViews: ['month']
});Example: Customize weekday name format:
// Portuguese with full day names
new SimpleCalendarJs('#calendar', {
locale: 'pt-PT',
weekdayFormat: 'long' // Domingo, Segunda-feira, Terça-feira...
});
// English with narrow format (single letters)
new SimpleCalendarJs('#calendar', {
locale: 'en-US',
weekdayFormat: 'narrow' // S, M, T, W, T, F, S
});Note: Different locales format the same option differently. Use weekdayFormat to control the style: 'narrow' (1-2 letters), 'short' (abbreviated), or 'long' (full name).
Register event handlers for user interactions:
| Callback | Parameters | Description |
|---|---|---|
fetchEvents | (start: Date, end: Date) | Async function to fetch events for the visible date range. Should return an array of event objects. |
onEventClick | (event: Object) | Called when an event is clicked |
onSlotClick | (date: Date) | Called when an empty time slot is clicked |
onViewChange | (view: String) | Called when the view changes (month/week/day) |
onNavigate | (start: Date, end: Date) | Called when navigating to a different date range |
onEventDrop | (event: Object, oldStart: Date, oldEnd: Date, newStart: Date, newEnd: Date) | Called when an event is dropped after being dragged |
Events returned from fetchEvents should have the following structure:
{
id: 'unique-id', // Required: Unique identifier
title: 'Event Title', // Required: Event name
start: Date, // Required: Start date/time
end: Date, // Required: End date/time
allDay: false, // Optional: All-day event flag
color: '#4f46e5', // Optional: Custom color (hex)
description: 'Details', // Optional: Event description (also used for tooltip)
tooltip: 'Custom tooltip' // Optional: Custom tooltip text (overrides description)
}Minute Precision: The calendar supports minute-level precision for event times. Events are positioned exactly according to their start/end times in week and day views. For example, an event starting at 9:15 AM will be positioned 15 minutes (25%) below the 9:00 AM hour line.
const calendar = new SimpleCalendarJs('#calendar', {
fetchEvents: async (start, end) => {
return [
{
id: '1',
title: 'Team Meeting',
start: new Date(2024, 0, 15, 9, 15), // 9:15 AM
end: new Date(2024, 0, 15, 10, 45), // 10:45 AM
color: '#4f46e5'
},
{
id: '2',
title: 'Lunch Break',
start: new Date(2024, 0, 15, 12, 30), // 12:30 PM
end: new Date(2024, 0, 15, 13, 30), // 1:30 PM
allDay: false,
color: '#059669'
}
];
},
onEventClick: (event) => {
alert(`Clicked: ${event.title}`);
},
onSlotClick: (date) => {
console.log('Create event at:', date);
}
});SimpleCalendarJs relies on JavaScript's native Date object for timezone handling, which means events are automatically displayed in the user's local timezone.
fetchEvents: async (start, end) => {
const response = await fetch(`/api/events?start=${start}&end=${end}`);
const events = await response.json();
// Backend returns ISO 8601 strings with timezone info
// Example: "2024-03-15T10:00:00Z" (UTC)
// or: "2024-03-15T10:00:00-05:00" (EST)
return events.map(event => ({
...event,
start: new Date(event.start), // Automatically converts to local timezone
end: new Date(event.end)
}));
}// BAD: "2024-03-15T10:00:00" (no timezone)
// JavaScript interprets this as LOCAL time, not UTC
// This can cause issues for users in different timezonesScenario: Your server stores events in UTC, users are in different timezones
// Server returns (stored in UTC):
{
"title": "Team Meeting",
"start": "2024-03-15T14:00:00Z", // 2:00 PM UTC
"end": "2024-03-15T15:00:00Z" // 3:00 PM UTC
}
// User in New York (EST, UTC-5):
// Calendar displays: 9:00 AM - 10:00 AM
// User in London (GMT, UTC+0):
// Calendar displays: 2:00 PM - 3:00 PM
// User in Tokyo (JST, UTC+9):
// Calendar displays: 11:00 PM - 12:00 AMIntl.DateTimeFormat which respects the user's locale and timezone{
"events": [
{
"id": 1,
"title": "Global Team Standup",
"start": "2024-03-15T14:00:00Z",
"end": "2024-03-15T14:30:00Z",
"description": "Daily standup - all timezones welcome"
}
]
}Summary: As long as your backend sends properly formatted ISO 8601 date strings with timezone information (e.g., with 'Z' for UTC or timezone offset like '-05:00'), the calendar will automatically handle timezone conversion for each user's location.
SimpleCalendarJs includes built-in tooltip support for displaying additional event information on hover.
Tooltips appear when you hover over an event for 400ms. They display content based on the following priority:
const events = [
{
id: 1,
title: 'Team Meeting',
start: new Date(2024, 2, 15, 10, 0),
end: new Date(2024, 2, 15, 11, 0),
tooltip: 'Weekly team sync\nDiscuss Q1 roadmap' // Custom tooltip
},
{
id: 2,
title: 'Client Call',
start: new Date(2024, 2, 15, 14, 0),
end: new Date(2024, 2, 15, 15, 0),
description: 'Requirements gathering\nPrepare demo' // Used as tooltip
},
{
id: 3,
title: 'Code Review',
start: new Date(2024, 2, 15, 16, 0),
end: new Date(2024, 2, 15, 17, 0)
// No tooltip/description - will show title
}
];Use \n (newline character) in your tooltip or description text to create multiple lines:
{
id: 1,
title: 'Project Kickoff',
start: new Date(2024, 2, 20, 9, 0),
end: new Date(2024, 2, 20, 10, 30),
tooltip: 'Project Kickoff Meeting\n\nAgenda:\n- Introductions\n- Timeline review\n- Q&A session\n\nLocation: Conference Room A'
}Tooltips automatically adjust their position to stay visible:
You can disable tooltips globally using the showTooltips option:
const calendar = new SimpleCalendarJs('#calendar', {
showTooltips: false, // Disable all tooltips
fetchEvents: async (start, end) => { /* ... */ }
});Tooltips use CSS custom properties and can be customized:
:root {
--cal-tooltip-bg: #1f2937; /* Background color */
--cal-tooltip-text: #f9fafb; /* Text color */
--cal-tooltip-border: #374151; /* Border color */
--cal-tooltip-max-width: 250px; /* Maximum width */
--cal-tooltip-padding: 8px 12px; /* Inner padding */
--cal-tooltip-radius: 6px; /* Border radius */
--cal-tooltip-font-size: 12px; /* Font size */
--cal-tooltip-offset: 8px; /* Distance from event */
}Limitations: Tooltips display plain text only (no HTML rendering). Special characters are automatically escaped for security. Maximum width is 250px by default (customizable via CSS variables).
SimpleCalendarJs supports drag and drop for moving events and resizing them to change their duration.
const calendar = new SimpleCalendarJs('#calendar', {
enableDragDrop: true, // Enable moving events
enableResize: true, // Enable resizing events
onEventDrop: (event, oldStart, oldEnd, newStart, newEnd) => {
// Detect if this is a move or resize
const isMoved = oldStart.getTime() !== newStart.getTime();
const isResized = oldEnd.getTime() !== newEnd.getTime() && !isMoved;
if (isMoved) {
console.log(`Event "${event.title}" moved to ${newStart}`);
} else if (isResized) {
console.log(`Event "${event.title}" resized to end at ${newEnd}`);
}
// Update your backend
await fetch(`/api/events/${event.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
start: newStart.toISOString(),
end: newEnd.toISOString(),
allDay: event.allDay
})
});
}
});enableDragDrop)How It Works:
Cross-Boundary Conversion:
When dragging events between different sections:
Timed Event → All-Day Section (Week/Day Views):
All-Day Event → Timed Section (Week/Day Views):
Month View:
enableResize)Horizontal Resize (All-Day Events):
Vertical Resize (Timed Events):
The onEventDrop callback receives the same parameters for both move and resize operations:
| Parameter | Type | Description |
|---|---|---|
event | Object | The updated event object (with new start/end) |
oldStart | Date | Original start date/time |
oldEnd | Date | Original end date/time |
newStart | Date | New start date/time |
newEnd | Date | New end date/time |
Detecting Operation Type:
oldStart !== newStartoldStart === newStart and oldEnd !== newEndImportant Notes:
onEventDrop callbackcalendar.refresh() to revert to the previous stateThe monthTimedEventStyle option controls how timed events are displayed in month view:
'list')Schedule-style display with horizontal layout:
showTimeInItems is enabled)const calendar = new SimpleCalendarJs('#calendar', {
monthTimedEventStyle: 'list', // Default
showTimeInItems: true // Shows time next to dot
});'block')Traditional calendar block display:
const calendar = new SimpleCalendarJs('#calendar', {
monthTimedEventStyle: 'block'
});Note: This option only affects timed events in month view. All-day events always display as blocks, and week/day views always use block style with duration-based heights.
Display upcoming events in a chronological list format. Perfect for mobile devices and quick overview of upcoming events.
const calendar = new SimpleCalendarJs('#calendar', {
defaultView: 'list', // Start in list view
enabledViews: ['month', 'week', 'day', 'list'], // Include list in views
listDaysForward: 30 // Show next 30 days (default)
});listDaysForward optionList view always displays events from the current date/time forward, unlike other views which are navigable:
// Show next 90 days in list view
new SimpleCalendarJs('#calendar', {
defaultView: 'list',
enabledViews: ['month', 'list'], // Only month and list views
listDaysForward: 90,
fetchEvents: async (start, end) => {
// Your event fetching logic
}
});Note: List view is opt-in. Add 'list' to the enabledViews array to enable it.
Programmatically control the calendar:
| Method | Parameters | Description |
|---|---|---|
setView(view) | 'month' | 'week' | 'day' | 'list' | Switch to a different view |
navigate(direction) | number | Navigate by offset: 1 = next, -1 = previous |
goToDate(date) | Date | Jump to a specific date |
goToToday() | - | Jump to today's date |
refresh() | - | Clear event cache and re-fetch events |
destroy() | - | Remove calendar and cleanup event listeners |
const calendar = new SimpleCalendarJs('#calendar', { /* options */ });
// Switch to week view
calendar.setView('week');
// Navigate to next week
calendar.navigate(1);
// Jump to a specific date
calendar.goToDate(new Date(2024, 5, 15));
// Go to today
calendar.goToToday();
// Refresh calendar (clear cache and re-fetch)
calendar.refresh();
// Cleanup when done
calendar.destroy();SimpleCalendarJs intelligently caches fetched events to minimize unnecessary network requests:
calendar.refresh() when events change externally (added, updated, or deleted)How it works:
listDaysForward)// Month view Feb 2026: Fetches Jan 28 - Mar 1 (full month grid)
calendar.setView('month'); // ✓ Fetch: Jan 28 - Mar 1
// Switch to week view (Feb 20-26): Already in cache, no fetch
calendar.setView('week'); // ✗ No fetch (instant)
// Switch to day view (Feb 22): Already in cache, no fetch
calendar.setView('day'); // ✗ No fetch (instant)
// Navigate next week (Feb 27 - Mar 5): Extends beyond cache
// Fetches March's full month grid (Mar 1 - Apr 5)
calendar.navigate(1); // ✓ Fetch: Mar 1 - Apr 5
// Navigate next week (Mar 6-12): Already in March's cache
calendar.navigate(1); // ✗ No fetch (instant)
// Navigate previous week (Feb 27 - Mar 5): Partially outside cache
// Fetches February's full month grid (Jan 28 - Mar 1)
calendar.navigate(-1); // ✓ Fetch: Jan 28 - Mar 1
// After external event changes, refresh to clear cache
addEventToDatabase(newEvent);
calendar.refresh(); // ✓ Fetch (clears cache)The calendar doesn't include built-in persistence - this is intentionally left to your application so you have full control over how and where preferences are stored.
// Restore saved preferences or use defaults
const savedView = localStorage.getItem('calendarView') || 'month';
const savedDate = localStorage.getItem('calendarDate');
const calendar = new SimpleCalendarJs('#calendar', {
defaultView: savedView,
defaultDate: savedDate ? new Date(savedDate) : null,
// Save view changes
onViewChange: (view) => {
localStorage.setItem('calendarView', view);
},
// Save navigation (current date)
onNavigate: (startDate) => {
localStorage.setItem('calendarDate', startDate.toISOString());
}
});// Same as localStorage but survives only for the current tab/session
const calendar = new SimpleCalendarJs('#calendar', {
defaultView: sessionStorage.getItem('calendarView') || 'month',
onViewChange: (view) => sessionStorage.setItem('calendarView', view),
onNavigate: (start) => sessionStorage.setItem('calendarDate', start.toISOString())
});// Read from URL
const params = new URLSearchParams(window.location.search);
const view = params.get('view') || 'month';
const date = params.get('date') ? new Date(params.get('date')) : null;
const calendar = new SimpleCalendarJs('#calendar', {
defaultView: view,
defaultDate: date,
onViewChange: (newView) => {
const url = new URL(window.location);
url.searchParams.set('view', newView);
window.history.pushState({}, '', url);
},
onNavigate: (startDate) => {
const url = new URL(window.location);
url.searchParams.set('date', startDate.toISOString().split('T')[0]);
window.history.pushState({}, '', url);
}
});function MyCalendar() {
const [view, setView] = useState(
() => localStorage.getItem('calendarView') || 'month'
);
const [currentDate, setCurrentDate] = useState(
() => {
const saved = localStorage.getItem('calendarDate');
return saved ? new Date(saved) : new Date();
}
);
const handleViewChange = (newView) => {
setView(newView);
localStorage.setItem('calendarView', newView);
};
const handleNavigate = (startDate) => {
setCurrentDate(startDate);
localStorage.setItem('calendarDate', startDate.toISOString());
};
return (
<SimpleCalendarJsReact
defaultView={view}
defaultDate={currentDate}
onViewChange={handleViewChange}
onNavigate={handleNavigate}
fetchEvents={fetchEvents}
/>
);
}// composables/useCalendarPreferences.js
import { ref, watch } from 'vue';
export function useCalendarPreferences() {
const view = ref(localStorage.getItem('calendarView') || 'month');
const currentDate = ref(
localStorage.getItem('calendarDate')
? new Date(localStorage.getItem('calendarDate'))
: new Date()
);
watch(view, (newView) => {
localStorage.setItem('calendarView', newView);
});
watch(currentDate, (newDate) => {
localStorage.setItem('calendarDate', newDate.toISOString());
});
return { view, currentDate };
}
// In component
<script setup>
import { useCalendarPreferences } from './composables/useCalendarPreferences';
const { view, currentDate } = useCalendarPreferences();
const handleViewChange = (newView) => {
view.value = newView;
};
const handleNavigate = (startDate) => {
currentDate.value = startDate;
};
</script>
<template>
<SimpleCalendarJsVue
:defaultView="view"
:defaultDate="currentDate"
@viewChange="handleViewChange"
@navigate="handleNavigate"
/>
</template>// Load preferences from your API
const preferences = await fetch('/api/user/calendar-preferences').then(r => r.json());
const calendar = new SimpleCalendarJs('#calendar', {
defaultView: preferences.view || 'month',
defaultDate: preferences.lastViewedDate ? new Date(preferences.lastViewedDate) : null,
onViewChange: async (view) => {
// Debounce to avoid too many API calls
clearTimeout(window.savePreferencesTimeout);
window.savePreferencesTimeout = setTimeout(() => {
fetch('/api/user/calendar-preferences', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ view })
});
}, 1000);
}
});Common preferences to save:
'month', 'week', 'day', or 'list'Note: The calendar is designed to be stateless - all state management is your responsibility, giving you full flexibility over storage method, persistence duration, and privacy controls.
SimpleCalendarJs supports dark mode and color customization via CSS custom properties.
Toggle dark mode by adding the uc-dark class to the calendar container:
// Enable dark mode
calendar._root.classList.add('uc-dark');
// Disable dark mode
calendar._root.classList.remove('uc-dark');
// Toggle dark mode
calendar._root.classList.toggle('uc-dark', isDark);Target the .uc-calendar class to customize light mode:
.uc-calendar {
/* Primary color */
--cal-primary: #10b981; /* Green theme */
--cal-primary-dark: #059669;
--cal-primary-light: #d1fae5;
/* Today indicator */
--cal-today-bg: #d1fae5;
--cal-today-text: #059669;
}Target .uc-calendar.uc-dark to customize dark mode:
.uc-calendar.uc-dark {
/* Dark mode colors */
--cal-bg: #1f2937;
--cal-bg-secondary: #111827;
--cal-text: #f9fafb;
--cal-border: #374151;
/* Dark mode today/selected indicators */
--cal-today-bg: #065f46; /* Custom dark green */
--cal-selected-bg: #047857;
}Example with a complete brand color scheme:
/* Light mode - Yellow theme */
.uc-calendar {
--cal-primary: #eab308; /* yellow-500 */
--cal-primary-dark: #ca8a04; /* yellow-600 */
--cal-primary-light: #fef9c3; /* yellow-100 */
--cal-today-bg: #fef9c3;
--cal-today-text: #854d0e;
}
/* Dark mode - Yellow theme */
.uc-calendar.uc-dark {
--cal-primary: #eab308;
--cal-primary-dark: #facc15;
--cal-primary-light: #713f12;
--cal-today-bg: #713f12; /* yellow-900 */
--cal-selected-bg: #854d0e; /* yellow-800 */
}| Variable | Category | Description |
|---|---|---|
| --cal-primary | Colors | Primary theme color |
| --cal-primary-dark | Colors | Darker primary (hover states) |
| --cal-primary-light | Colors | Lighter primary (backgrounds) |
| --cal-bg | Colors | Background color |
| --cal-bg-secondary | Colors | Secondary background |
| --cal-text | Colors | Primary text color |
| --cal-text-subtle | Colors | Subtle text color |
| --cal-border | Colors | Border color |
| --cal-today-bg | Colors | Today indicator background |
| --cal-selected-bg | Colors | Selected date background |
| --cal-font-size | Sizing | Base font size (default: 13px) |
| --cal-hour-height | Sizing | Hour row height (default: 60px) |
| --cal-event-height | Sizing | Event bar height (default: 22px) |
| --cal-tooltip-* | Tooltips | Tooltip colors, sizing, typography |
| --cal-loading-bg | Loading | Loading spinner overlay background (default: rgba(255, 255, 255, 0.7) in light mode, rgba(31, 41, 55, 0.7) in dark mode) |
Tip: Use .uc-calendar.uc-dark to override dark mode colors separately from light mode. This allows you to create cohesive themes that work in both modes.
Use the React wrapper for seamless integration with React applications.
import SimpleCalendarJsReact from './simple-calendar-js-react.jsx';
import './simple-calendar-js.css';import { useState } from 'react';
import SimpleCalendarJsReact from './simple-calendar-js-react.jsx';
function App() {
const [isDark, setIsDark] = useState(false);
const fetchEvents = async (start, end) => {
const response = await fetch(`/api/events?start=${start}&end=${end}`);
return response.json();
};
const handleEventClick = (event) => {
console.log('Event clicked:', event);
};
return (
<>
<button onClick={() => setIsDark(!isDark)}>
Toggle Theme
</button>
<SimpleCalendarJsReact
defaultView="month"
defaultDate={new Date(2024, 5, 15)}
weekStartsOn={1}
darkMode={isDark}
fetchEvents={fetchEvents}
onEventClick={handleEventClick}
onSlotClick={(date) => console.log('Slot clicked:', date)}
onViewChange={(view) => console.log('View changed:', view)}
style={{ height: '600px' }}
/>
</>
);
}import { useRef } from 'react';
function App() {
const calRef = useRef();
const handleNextWeek = () => {
calRef.current.setView('week');
calRef.current.navigate(1);
};
return (
<>
<button onClick={handleNextWeek}>Next Week</button>
<SimpleCalendarJsReact ref={calRef} />
</>
);
}darkMode - Boolean prop for theme controlonEventClick, onSlotClick, onViewChange, onNavigate - Event handlersstyle, className - Apply to wrapper divUse the Vue 3 wrapper with Composition API.
import SimpleCalendarJsVue from './simple-calendar-js-vue.js';
import './simple-calendar-js.css';<script setup>
import { ref } from 'vue';
import SimpleCalendarJsVue from './simple-calendar-js-vue.js';
const isDark = ref(false);
const fetchEvents = async (start, end) => {
const response = await fetch(`/api/events?start=${start}&end=${end}`);
return response.json();
};
const handleEventClick = (event) => {
console.log('Event clicked:', event);
};
</script>
<template>
<button @click="isDark = !isDark">Toggle Theme</button>
<SimpleCalendarJsVue
:defaultView="'month'"
:defaultDate="new Date(2024, 5, 15)"
:weekStartsOn="1"
:darkMode="isDark"
:fetchEvents="fetchEvents"
@eventClick="handleEventClick"
@slotClick="(date) => console.log('Slot clicked:', date)"
@viewChange="(view) => console.log('View changed:', view)"
:style="{ height: '600px' }"
/>
</template><script setup>
import { ref } from 'vue';
const calendarRef = ref();
const handleNextWeek = () => {
calendarRef.value.setView('week');
calendarRef.value.navigate(1);
};
</script>
<template>
<button @click="handleNextWeek">Next Week</button>
<SimpleCalendarJsVue ref="calendarRef" />
</template>:darkMode - Boolean prop for theme control@eventClick, @slotClick, @viewChange, @navigate - Vue events:customClass - Apply CSS class to wrapperUse the Angular standalone component (or NgModule).
import { SimpleCalendarJsComponent } from './simple-calendar-js-angular.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [SimpleCalendarJsComponent],
// ...
})import { Component } from '@angular/core';
import { SimpleCalendarJsComponent } from './simple-calendar-js-angular.component';
@Component({
selector: 'app-calendar-demo',
standalone: true,
imports: [SimpleCalendarJsComponent],
template: `
<button (click)="isDark = !isDark">Toggle Theme</button>
<simple-calendar-js
[defaultView]="'month'"
[defaultDate]="new Date(2024, 5, 15)"
[weekStartsOn]="1"
[darkMode]="isDark"
[fetchEvents]="fetchEvents"
(eventClick)="handleEventClick($event)"
(slotClick)="handleSlotClick($event)"
(viewChange)="handleViewChange($event)"
[customStyle]="{ height: '600px' }"
></simple-calendar-js>
`
})
export class CalendarDemoComponent {
isDark = false;
fetchEvents = async (start: Date, end: Date) => {
const response = await fetch(`/api/events?start=${start}&end=${end}`);
return response.json();
};
handleEventClick(event: any) {
console.log('Event clicked:', event);
}
handleSlotClick(date: Date) {
console.log('Slot clicked:', date);
}
handleViewChange(view: string) {
console.log('View changed:', view);
}
}import { Component, ViewChild } from '@angular/core';
import { SimpleCalendarJsComponent } from './simple-calendar-js-angular.component';
@Component({
// ...
})
export class CalendarDemoComponent {
@ViewChild(SimpleCalendarJsComponent) calendar!: SimpleCalendarJsComponent;
handleNextWeek() {
this.calendar.setView('week');
this.calendar.navigate(1);
}
}@Input properties[darkMode] - Boolean input for theme control(eventClick), (slotClick), (viewChange), (navigate) - Angular outputs[customClass], [customStyle] - Apply to wrapper divCustomize the calendar appearance with CSS.
.my-green-calendar {
--cal-primary: #10b981;
--cal-primary-dark: #059669;
--cal-primary-light: #d1fae5;
}.my-calendar {
--cal-font-size: 14px;
--cal-event-height: 26px;
}/* Target all events */
.uc-calendar .uc-event {
border-radius: 6px;
font-weight: 600;
}
/* Target timed events in week/day view */
.uc-calendar .uc-timed-event {
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}| Class | Target |
|---|---|
.uc-calendar | Calendar root container |
.uc-dark | Dark mode modifier |
.uc-toolbar | Top toolbar |
.uc-event | Event elements |
.uc-timed-event | Timed events in week/day view |
.uc-today | Today's date cell |