Vanilla Calendar JS Library for Date Picking, Scheduling, and Timelines

Vanilla Calendar JS Library for Date Picking, Scheduling, and Timelines
Vanilla Calendar JS Library for Date Picking, Scheduling, and Timelines
CalendarJS is a feature-rich JavaScript calendar library that allows you to create calendars, date pickers, event schedules, and timelines in modern web apps.

Features:

  • Generate modal, inline, auto, and picker style calendars.
  • Pick single dates, date ranges, and date & time values.
  • Restrict selectable dates with valid date windows.
  • Change weekday order for local business calendars.
  • Show event markers inside the calendar grid.
  • Build day, week, and weekday schedule views.
  • Drag and resize schedule items in the grid.
  • Track schedule history with undo and redo actions.
  • Block editing in protected time ranges.
  • Switch timeline items across left, right, top, and bottom layouts.
  • Filter timeline output by month in monthly mode.
  • Convert ISO dates to Excel-style serial numbers.
  • Format dates into relative time labels.

Use cases:

  • Build a hotel booking form with date range and time selection.
  • Add a weekly staff planner to an internal operations dashboard.
  • Show a release history view inside a product changelog page.
  • Convert spreadsheet date values in import and export flows.

How to use it:

1. Install the package with NPM and import modules into your project:

npm install @calendarjs/ce
import { Calendar } from '@calendarjs/ce';
import { Schedule } from '@calendarjs/ce';
import { Timeline } from '@calendarjs/ce';

2. Or load it from a CDN:

<!-- Load the stylesheet first -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@calendarjs/ce/dist/style.min.css" />

<!-- Load LemonadeJS before CalendarJS in browser builds -->
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@calendarjs/ce/dist/index.min.js"></script>

3. Create an inline range calendar and a time picker

<div id="report-range"></div>
<input id="publish-at" />

<script>
  // Create an inline range calendar for a reporting window
  const reportRange = calendarjs.Calendar(document.getElementById('report-range'), {
    type: 'inline',
    range: true,
    grid: true,
    startingDay: 1,
    validRange: ['2026-04-01', '2026-05-31'],
    value: ['2026-04-12', '2026-04-19'],
    onchange: function(self, value) {
      // Read the selected range after every change
      console.log('Range value:', value);
    }
  });

  // Bind a popup calendar to an input field
  const publishAt = calendarjs.Calendar(document.getElementById('publish-at'), {
    type: 'default',
    input: document.getElementById('publish-at'),
    time: true,
    format: 'MMMM DD, YYYY HH:MI',
    value: '2026-04-20 15:45:00',
    onchange: function(self, value) {
      // Store the picked date and time in your form state
      console.log('Publish at:', value);
    }
  });

  // Open the popup calendar from code if you need a custom trigger
  publishAt.open();
</script>

4. Build a weekly schedule:

<div id="team-board"></div>

<script>
  // Seed the scheduler with a few meetings
  const teamBoard = calendarjs.Schedule(document.getElementById('team-board'), {
    type: 'week',
    value: '2026-04-20',
    grid: 30,
    overlap: false,
    validRange: ['08:00', '19:00'],
    data: [
      {
        guid: 'evt-101',
        title: 'Design review',
        date: '2026-04-21',
        start: '09:00',
        end: '10:30',
        color: '#b86e2f'
      },
      {
        guid: 'evt-102',
        title: 'Ops sync',
        date: '2026-04-22',
        start: '13:00',
        end: '14:00',
        color: '#5e7f4a'
      }
    ],
    oncreate: function(self, events) {
      // Persist new events after user edits
      console.log('Created:', events);
    },
    onchangeevent: function(self, newValue, oldValue) {
      // Track updates for autosave or audit logs
      console.log('Changed:', newValue, oldValue);
    },
    onerror: function(self, message) {
      // Show validation feedback in your UI
      console.log('Schedule error:', message);
    }
  });

  // Lock early morning and late evening blocks
  teamBoard.setReadOnly([['00:00', '08:00'], ['19:00', '23:59']]);

  // Add an event from code
  teamBoard.addEvents({
    guid: 'evt-103',
    title: 'Client handoff',
    date: '2026-04-23',
    start: '16:00',
    end: '17:00',
    color: '#9f5140'
  });
</script>

5. Generate a timeline:

<div id="release-timeline"></div>

<script>
  // Create a project timeline with dated milestones
  const releaseTimeline = calendarjs.Timeline(document.getElementById('release-timeline'), {
    type: 'monthly',
    align: 'left',
    order: 'asc',
    controls: true,
    data: [
      {
        title: 'Spec freeze',
        subtitle: 'Planning',
        description: 'The team locked scope for the next release cycle.',
        date: new Date('2026-04-02'),
        borderColor: '#b86e2f',
        borderStyle: 'solid'
      },
      {
        title: 'QA pass',
        subtitle: 'Validation',
        description: 'QA finished the final regression pass.',
        date: new Date('2026-04-11'),
        borderColor: '#5e7f4a',
        borderStyle: 'solid'
      },
      {
        title: 'Public launch',
        subtitle: 'Release',
        description: 'The new build went live to all users.',
        date: new Date('2026-04-18'),
        borderColor: '#9f5140',
        borderStyle: 'dashed'
      }
    ],
    onupdate: function(self) {
      // React to monthly filtering or data changes
      console.log('Timeline updated');
    }
  });

  // Move to the next month in monthly mode
  releaseTimeline.next();
  releaseTimeline.updateResult();
</script>

6. Use the helper utilities:

// Read the current UTC date string
const nowValue = calendarjs.Helpers.now();

// Convert an ISO date to an Excel style serial number
const serialValue = calendarjs.Helpers.dateToNum('2026-04-20 10:00:00');

// Convert the serial number back to a date string
const restoredDate = calendarjs.Helpers.numToDate(serialValue);

// Turn a timestamp into a relative label
const relativeLabel = calendarjs.Helpers.prettify('2026-04-19 10:00:00');

console.log(nowValue, serialValue, restoredDate, relativeLabel);

Configuration options:

Calendar options

  • type ('default' | 'auto' | 'picker' | 'inline'): Sets the calendar display mode.
  • format (string): Sets the output format for rendered values.
  • range (boolean): Turns range selection on or off.
  • value (number | string): Sets the initial calendar value.
  • numeric (boolean): Returns Excel style serial numbers in place of ISO strings.
  • footer (boolean): Shows or hides the footer controls.
  • time (boolean): Shows the hour and minute picker.
  • grid (boolean): Turns grid mode on or off.
  • placeholder (string): Sets placeholder text for bound inputs.
  • disabled (boolean): Locks the calendar UI.
  • startingDay (number): Sets the first weekday from 0 to 6.
  • validRange (number[] | string[]): Restricts selectable dates to a range.
  • data (Array<{date: string, [key: string]: any}>): Adds event data for calendar markers.
  • wheel (boolean): Turns mouse wheel view changes on or off.
  • input (HTMLInputElement | 'auto'): Binds the calendar to an input element.
  • initInput (boolean): Applies input setup and calendar classes.
  • onchange ((self: object, value: string) => void): Runs after the value changes.
  • onupdate ((self: object, value: string) => void): Runs after the view updates.
  • onclose ((self: object, origin: string) => void): Runs after the modal closes.
  • onopen ((self: object) => void): Runs after the modal opens.
  • onChange ((e: Event) => void): Exposes a React focused change hook.

Schedule options

  • type ('week' | 'day' | 'weekdays'): Sets the schedule view type.
  • weekly (boolean): Uses weekday columns in place of dated columns.
  • value (string): Sets the initial ISO date in YYYY-MM-DD format.
  • data (Schedule.Event[]): Loads the schedule with event records.
  • grid (number): Sets the grid step in minutes.
  • overlap (boolean): Permits overlapping events.
  • validRange (string[]): Restricts visible editing hours.
  • readOnlyRange (string[] | string[][]): Marks one or more time ranges as read only.
  • onbeforechange ((self: Instance, state: object) => boolean | void): Runs before a grid drag or resize change.
  • onchange ((self: Instance, state: object) => void): Runs after a grid state change.
  • onbeforecreate ((self: Instance, events: Event | Event[], e?: MouseEvent) => boolean | void): Runs before event creation.
  • oncreate ((self: Instance, events: Event | Event[], e?: MouseEvent) => void): Runs after event creation.
  • ondblclick ((self: Instance, event: Event) => void): Runs on event double click.
  • onedition ((self: Instance, event: Event) => void): Runs when editing starts.
  • ondelete ((self: Instance, event: Event) => void): Runs after event deletion.
  • onchangeevent ((self: Instance, newValue: Partial<Event>, oldValue: Partial<Event>) => void): Runs after event data changes.
  • onerror ((self: Instance, message: string) => void): Runs after validation errors.

Schedule event object

  • type (string | null): Sets the event type label.
  • title (string): Sets the event title.
  • start (string): Sets the start time in HH:MM.
  • end (string): Sets the end time in HH:MM.
  • guests (string): Stores guest data.
  • location (string): Stores a location label.
  • description (string): Stores descriptive text.
  • color (string): Sets the event color.
  • readonly (boolean): Locks the event from editing.
  • guid (string): Stores the unique event id.
  • date (string): Stores the ISO date when weekly is false.
  • weekday (number): Stores the weekday from 0 to 6 when weekly is true.

Timeline options

  • data (Timeline.Item[]): Loads the timeline with item records.
  • type ("monthly" | string): Sets the timeline mode.
  • align ("left" | "right" | "top" | "bottom" | string): Sets item alignment.
  • message (string): Sets the empty state message.
  • order ('asc' | 'desc' | undefined): Sets chronological order.
  • width (number): Sets container width.
  • height (number): Sets container height.
  • url (string): Sets a remote data URL.
  • remote (boolean): Turns remote loading on.
  • onupdate ((self: Object) => void): Runs after the visible timeline data updates.

Timeline item object

  • title (string): Sets the main item label.
  • subtitle (string): Sets the secondary label.
  • description (string): Sets the item body text.
  • date (string | Date): Sets the item date.
  • borderColor (string): Sets the item border color.
  • borderStyle (string): Sets the item border style.

API methods:

// Create a calendar instance
const calendar = calendarjs.Calendar(document.getElementById('calendar-root'), {
  type: 'inline'
});

// Open the calendar modal
calendar.open();

// Close the calendar modal
calendar.close({ origin: 'button' });

// Check modal state
calendar.isClosed();

// Switch the calendar view
calendar.setView('months');

// Move forward in the current view
calendar.next();

// Move backward in the current view
calendar.prev();

// Reset the selected value
calendar.reset();

// Read the current value
calendar.getValue();

// Write a new value
calendar.setValue('2026-04-24');

// Accept the current selection
calendar.update();


// Create a schedule instance
const schedule = calendarjs.Schedule(document.getElementById('schedule-root'), {
  type: 'week'
});

// Add one event
schedule.addEvents({
  guid: 'evt-201',
  title: 'Roadmap sync',
  date: '2026-04-24',
  start: '10:00',
  end: '11:00',
  color: '#b86e2f'
});

// Add multiple events
schedule.addEvents([
  {
    guid: 'evt-202',
    title: 'Editorial review',
    date: '2026-04-24',
    start: '12:00',
    end: '13:00',
    color: '#5e7f4a'
  },
  {
    guid: 'evt-203',
    title: 'Launch prep',
    date: '2026-04-25',
    start: '15:00',
    end: '16:00',
    color: '#9f5140'
  }
]);

// Update an event by guid
schedule.updateEvent('evt-201', {
  title: 'Roadmap sync v2',
  start: '10:30'
});

// Update an event by object reference
const firstRecord = schedule.getData()[0];
schedule.updateEvent(firstRecord, {
  end: '11:30'
});

// Delete by guid
schedule.deleteEvents('evt-202');

// Delete by object
schedule.deleteEvents(firstRecord);

// Delete multiple records
schedule.deleteEvents(['evt-201', 'evt-203']);

// Clear the current visual selection
schedule.resetSelection();

// Restrict editable hours
schedule.setRange(['09:00', '18:00']);

// Mark time ranges as read only
schedule.setReadOnly([['00:00', '09:00'], ['18:00', '23:59']]);

// Read all schedule data
schedule.getData();

// Replace all schedule data
schedule.setData([
  {
    guid: 'evt-301',
    title: 'Support block',
    date: '2026-04-26',
    start: '11:00',
    end: '12:00',
    color: '#b86e2f'
  }
]);

// Read the DOM node for an event
schedule.getEvent('evt-301');

// Render the schedule again
schedule.render();

// Undo the last change
schedule.undo();

// Redo the last undone change
schedule.redo();

// Move to the next period
schedule.next();

// Move to the previous period
schedule.prev();


// Create a timeline instance
const timeline = calendarjs.Timeline(document.getElementById('timeline-root'), {
  type: 'monthly',
  data: []
});

// Read the bound timeline data
timeline.data;

// Move to the next month in monthly mode
timeline.next();

// Move to the previous month in monthly mode
timeline.prev();

// Rebuild the visible item list
timeline.updateResult();

// Fetch remote data when remote mode is active
timeline.fetchRemote();


// Convert a value to two digits
calendarjs.Helpers.two(7);

// Validate a Date object
calendarjs.Helpers.isValidDate(new Date());

// Validate an ISO date string
calendarjs.Helpers.isValidDateFormat('2026-04-24');

// Convert a Date to a string
calendarjs.Helpers.toString(new Date(), false);

// Convert a string into an array
calendarjs.Helpers.toArray('2026-04-24 12:30:00');

// Convert an array into a string date
calendarjs.Helpers.arrayToStringDate([2026, 4, 24, 12, 30, 0]);

// Convert a Date or string to an Excel style serial
calendarjs.Helpers.dateToNum('2026-04-24 12:30:00');

// Convert an Excel style serial back to a string
calendarjs.Helpers.numToDate(46136.520833333336);

// Convert an Excel style serial to an array
calendarjs.Helpers.numToDate(46136.520833333336, true);

// Convert a timestamp into a relative label
calendarjs.Helpers.prettify('2026-04-23 12:30:00');

// Update every .prettydate node on the page
calendarjs.Helpers.prettifyAll();

// Read the current date string
calendarjs.Helpers.now();

// Read localized weekday names
calendarjs.Helpers.weekdays;

// Read localized short weekday names
calendarjs.Helpers.weekdaysShort;

// Read localized month names
calendarjs.Helpers.months;

// Read localized short month names
calendarjs.Helpers.monthsShort;


// Set custom labels
calendarjs.setDictionary({
  Reset: 'Clear',
  Done: 'Apply'
});

// Read package metadata
calendarjs.about();

Events:

// Run after a calendar value changes
calendarjs.Calendar(document.getElementById('calendar-a'), {
  onchange: function(self, value) {
    console.log('Calendar change:', value);
  }
});

// Run after the calendar view updates
calendarjs.Calendar(document.getElementById('calendar-b'), {
  onupdate: function(self, value) {
    console.log('Calendar update:', value);
  }
});

// Run after the calendar modal closes
calendarjs.Calendar(document.getElementById('calendar-c'), {
  onclose: function(self, origin) {
    console.log('Calendar closed from:', origin);
  }
});

// Run after the calendar modal opens
calendarjs.Calendar(document.getElementById('calendar-d'), {
  onopen: function(self) {
    console.log('Calendar opened');
  }
});

// React focused change callback
calendarjs.Calendar(document.getElementById('calendar-e'), {
  onChange: function(e) {
    console.log('React style change event:', e);
  }
});


// Run before a schedule drag or resize change
calendarjs.Schedule(document.getElementById('schedule-a'), {
  onbeforechange: function(self, state) {
    console.log('Before grid change:', state);
    return true;
  }
});

// Run after a schedule grid change
calendarjs.Schedule(document.getElementById('schedule-b'), {
  onchange: function(self, state) {
    console.log('Grid changed:', state);
  }
});

// Run before creating events
calendarjs.Schedule(document.getElementById('schedule-c'), {
  onbeforecreate: function(self, events, e) {
    console.log('Before create:', events, e);
    return true;
  }
});

// Run after creating events
calendarjs.Schedule(document.getElementById('schedule-d'), {
  oncreate: function(self, events, e) {
    console.log('Created:', events, e);
  }
});

// Run on event double click
calendarjs.Schedule(document.getElementById('schedule-e'), {
  ondblclick: function(self, event) {
    console.log('Double click:', event);
  }
});

// Run when event editing starts
calendarjs.Schedule(document.getElementById('schedule-f'), {
  onedition: function(self, event) {
    console.log('Editing:', event);
  }
});

// Run after deleting an event
calendarjs.Schedule(document.getElementById('schedule-g'), {
  ondelete: function(self, event) {
    console.log('Deleted:', event);
  }
});

// Run after event data changes
calendarjs.Schedule(document.getElementById('schedule-h'), {
  onchangeevent: function(self, newValue, oldValue) {
    console.log('Event changed:', newValue, oldValue);
  }
});

// Run after schedule validation errors
calendarjs.Schedule(document.getElementById('schedule-i'), {
  onerror: function(self, message) {
    console.log('Schedule error:', message);
  }
});


// Run after timeline data updates
calendarjs.Timeline(document.getElementById('timeline-a'), {
  onupdate: function(self) {
    console.log('Timeline updated:', self);
  }
});

Alternatives:

  • FullCalendar: Handles large calendar apps with month, week, resource, and drag editing views.
  • TOAST UI Calendar: Ships a full calendar UI with multiple calendar layers and template hooks.

The post Vanilla Calendar JS Library for Date Picking, Scheduling, and Timelines appeared first on CSS Script.


Discover more from RSS Feeds Cloud

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Discover more from RSS Feeds Cloud

Subscribe now to keep reading and get access to the full archive.

Continue reading