Config-driven, data-source agnostic scheduler/calendar component built with pure HTML, CSS, and JavaScript
npm install innocore-schedulerbash
npm install @innocore/scheduler
`
Basic Usage
`html
`
Configuration
$3
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container', // Container selector or element
view: 'week', // Initial view: 'day', 'week', 'month', 'agenda'
currentDate: new Date(), // Initial date
startHour: 8, // Start hour for day/week views
endHour: 18, // End hour for day/week views
hourHeight: 60, // Height per hour in pixels
timezone: 'local', // Display timezone
slotClickEnabled: true, // Enable click to create events
events: [] // Initial events array
});
`
$3
The scheduler provides complete control over which UI elements and interactions are available:
#### Configurable Views
Control which calendar views are available to users:
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
// Only show Week and Month views (hide Day and Agenda)
enabledViews: ['week', 'month']
// Or only show a single view
// enabledViews: ['week']
// Default: ['day', 'week', 'month', 'agenda']
});
`
Valid view names: 'day', 'week', 'month', 'agenda'
#### Read-Only Mode
Make the scheduler completely read-only (no editing or creating):
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
// Enable read-only mode
readOnly: true
// Default: false
});
`
When readOnly: true:
- All event creation buttons are hidden
- Clicking on time slots does nothing
- Clicking on events does not open edit modal
- Event tooltips show information but no Edit/Delete buttons
- Perfect for displaying schedules that should not be modified
#### Timezone Selector Visibility
Control whether the timezone dropdown is visible:
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
// Hide the timezone selector
showTimezoneSelector: false
// Default: true
});
`
#### Export Buttons Configuration
Control which export format buttons are available in the toolbar:
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
// Option 1: Show all export formats
showExportButtons: true
// Option 2: Show specific formats only
showExportButtons: ['json', 'csv'] // Only JSON and CSV
// Option 3: Show no export buttons (default)
showExportButtons: false
});
`
Available export formats: 'json', 'csv', 'excel', 'ical'
Examples:
`javascript
// Only JSON and CSV exports
showExportButtons: ['json', 'csv']
// Only Excel export
showExportButtons: ['excel']
// All formats
showExportButtons: true // or ['json', 'csv', 'excel', 'ical']
// No export buttons
showExportButtons: false
`
$3
#### Example 1: Read-Only Schedule Display
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
enabledViews: ['week'], // Only week view
readOnly: true, // No editing or creating
showTimezoneSelector: false, // Hide timezone dropdown
eventSources: [fetchScheduleData()] // Load events from API
});
`
#### Example 2: Minimal Configuration
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
enabledViews: ['month'], // Month view only
showTimezoneSelector: false // Hide timezone selector
});
`
#### Example 3: Full Featured with Custom Fields
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
enabledViews: ['day', 'week', 'month'],
showTimezoneSelector: true, // Show timezone selector
eventFormFields: customFields // Custom event fields
});
`
Configurable Event Fields
One of the key features of @innocore/scheduler is fully configurable event fields. Event fields are not hardcoded - they are defined through configuration.
$3
Each field configuration object supports the following properties:
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| key | String | Yes | Data key for the field (maps to data source) |
| label | String | Yes | Display label in the form |
| control | String | Yes | Input control type (see below) |
| dataType | String | No | Expected data type (for validation) |
| required | Boolean | No | Whether field is mandatory |
| placeholder | String | No | Placeholder text for input |
| default | Any | No | Default value if not provided |
| options | Array | No | Options for select/dropdown controls |
| min | Number/String | No | Minimum value (for number/date inputs) |
| max | Number/String | No | Maximum value (for number/date inputs) |
| pattern | String | No | Regex pattern for validation |
| rows | Number | No | Number of rows (for textarea) |
$3
- text - Single-line text input
- textarea - Multi-line text input
- date - Date picker
- time - Time picker
- datetime-local - Date and time picker
- number - Number input
- email - Email input
- tel - Telephone input
- url - URL input
- checkbox - Checkbox
- select - Dropdown select
$3
If not specified, the scheduler uses these default fields:
`javascript
[
{
key: 'title',
label: 'Event Title',
control: 'text',
required: true,
placeholder: 'Enter event title'
},
{
key: 'startDate',
label: 'Start Date & Time',
control: 'datetime-local',
required: true
},
{
key: 'endDate',
label: 'End Date & Time',
control: 'datetime-local',
required: true
},
{
key: 'location',
label: 'Location',
control: 'text',
placeholder: 'Add location'
},
{
key: 'description',
label: 'Description',
control: 'textarea',
placeholder: 'Add description',
rows: 3
}
]
`
$3
You can completely customize the event fields:
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
eventFormFields: [
{
key: 'title',
label: 'Meeting Title',
control: 'text',
required: true,
placeholder: 'Enter meeting title',
maxLength: 100
},
{
key: 'organizer',
label: 'Organizer',
control: 'text',
required: true,
placeholder: 'Enter organizer name'
},
{
key: 'startDate',
label: 'Start Time',
control: 'datetime-local',
required: true
},
{
key: 'endDate',
label: 'End Time',
control: 'datetime-local',
required: true
},
{
key: 'meetingType',
label: 'Meeting Type',
control: 'select',
required: true,
options: [
{ value: 'internal', label: 'Internal Meeting' },
{ value: 'client', label: 'Client Meeting' },
{ value: 'review', label: 'Review Meeting' }
]
},
{
key: 'location',
label: 'Location',
control: 'text',
placeholder: 'Conference room or online link'
},
{
key: 'attendees',
label: 'Number of Attendees',
control: 'number',
min: 1,
max: 100,
default: 1
},
{
key: 'isVirtual',
label: 'Virtual Meeting',
control: 'checkbox'
},
{
key: 'notes',
label: 'Meeting Notes',
control: 'textarea',
rows: 4,
placeholder: 'Add meeting notes or agenda'
},
{
key: 'priority',
label: 'Priority',
control: 'select',
options: ['Low', 'Medium', 'High', 'Urgent']
}
]
});
`
$3
The scheduler automatically maintains two-way data binding:
UI → Data: When users create or edit events through the form, the data is automatically updated.
Data → UI: When you update events programmatically, the UI automatically reflects the changes.
`javascript
// Programmatic updates automatically reflect in UI
scheduler.addEvent({
id: '123',
title: 'New Event',
startDate: '2026-01-23T14:00:00',
endDate: '2026-01-23T15:00:00',
organizer: 'John Doe',
meetingType: 'client'
});
// Get current events (with all custom fields)
const events = scheduler.getEvents();
// Update event
scheduler.updateEvent('123', {
title: 'Updated Event',
priority: 'High'
});
// Delete event
scheduler.deleteEvent('123');
`
Data Source Mapping
Your event data can come from any source (REST API, GraphQL, Database, etc.) as long as it maps to the configured fields:
`javascript
// Example: Fetch from API and map to scheduler
fetch('/api/meetings')
.then(response => response.json())
.then(apiData => {
const events = apiData.map(meeting => ({
id: meeting.meetingId,
title: meeting.subject,
startDate: meeting.startTime,
endDate: meeting.endTime,
organizer: meeting.createdBy,
location: meeting.roomName,
meetingType: meeting.type,
isVirtual: meeting.hasOnlineLink
}));
scheduler.config.events = events;
scheduler.refresh();
});
`
Recurring Events
The scheduler supports recurring events with configurable patterns:
`javascript
{
id: '1',
title: 'Daily Standup',
startDate: '2026-01-22T09:00:00',
endDate: '2026-01-22T09:15:00',
isRecurring: true,
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;UNTIL=20260228T000000Z'
}
`
Recurrence patterns supported:
- Daily: FREQ=DAILY;INTERVAL=1
- Weekly: FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR
- Monthly: FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=15
Timezone Support
The scheduler includes built-in timezone conversion:
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
timezone: 'America/New_York', // Display in ET
events: [
{
id: '1',
title: 'Team Meeting',
startDate: '2026-01-22T10:00:00Z', // UTC time
endDate: '2026-01-22T11:00:00Z' // Displays as 5:00 AM ET
}
]
});
`
Available timezones:
- local - User's local timezone
- UTC - Coordinated Universal Time
- America/New_York - Eastern Time
- America/Chicago - Central Time
- America/Denver - Mountain Time
- America/Los_Angeles - Pacific Time
- Europe/London - GMT/BST
- Europe/Paris - Central European Time
- Asia/Tokyo - Japan Standard Time
- Asia/Kolkata - India Standard Time
API Methods
$3
`javascript
// Add event
scheduler.addEvent(eventData);
// Update event
scheduler.updateEvent(eventId, updatedData);
// Delete event
scheduler.deleteEvent(eventId);
// Get all events
const events = scheduler.getEvents();
// Get events in date range
const events = scheduler.getEventsInRange(startDate, endDate);
`
$3
`javascript
// Change view
scheduler.changeView('month');
// Navigate to specific date
scheduler.goToDate(new Date('2026-02-01'));
// Refresh display
scheduler.refresh();
`
$3
`javascript
// Export to iCalendar format
const icalData = scheduler.exportToICal();
// Import from iCalendar
scheduler.importFromICal(icalString);
// Export to JSON
const jsonData = JSON.stringify(scheduler.getEvents());
`
Event Callbacks
`javascript
const scheduler = new Scheduler.default({
container: '#scheduler-container',
// Called when an event is created
onEventCreate: (event) => {
console.log('Event created:', event);
},
// Called when an event is updated
onEventUpdate: (eventId, updatedData) => {
console.log('Event updated:', eventId, updatedData);
},
// Called when an event is deleted
onEventDelete: (eventId) => {
console.log('Event deleted:', eventId);
},
// Called when view changes
onViewChange: (view) => {
console.log('View changed to:', view);
},
// Called when date changes
onDateChange: (date) => {
console.log('Date changed to:', date);
},
// Called when a time slot is clicked
onSlotClick: (slotInfo) => {
console.log('Slot clicked:', slotInfo);
}
});
`
Styling
The scheduler uses CSS custom properties for easy theming:
`css
:root {
--sch-color-calendar: #4f46e5;
--sch-color-event-normal: #716ae9;
--sch-color-event-recurring: #c43081;
--sch-color-bg-main: #fff;
--sch-color-border: #e5e7eb;
--sch-color-text: #111827;
}
``