JavaScript Timeline

JavaScript Timeline

Pico Library

Built on CalendarJS Timeline: This reactive timeline component is powered by CalendarJS Timeline, the core lightweight timeline engine (2.1KB gzipped) with advanced features. LemonadeJS adds reactive data binding and framework integration (Vue, React, Angular) on top of the CalendarJS foundation.

The LemonadeJS JavaScript Timeline is a framework-agnostic plugin designed for timeline creation, supporting Vue, React, and Angular integration. It facilitates the construction of logs, event timelines, and roadmaps, providing options for customization such as color adjustments, content modification, and control over point positioning. The plugin includes features for automatically grouping events by month and navigation controls, aiding in organizing and displaying timeline data.

Timeline Component Family

CalendarJS Timeline - Core Component

The underlying timeline engine powering this reactive wrapper. CalendarJS Timeline can be used standalone for non-reactive applications:

  • Lightweight: 2.1KB gzipped
  • Framework-agnostic: Works with vanilla JS, React, Vue, Angular
  • Full-featured: Monthly navigation, sorting, alignment controls
  • Customizable: Border styles, colors, positioning

Perfect for: Standalone timelines, event logs, project roadmaps, activity feeds

Explore CalendarJS Timeline

CalendarJS Schedule - Event Scheduling

For interactive drag-and-drop event scheduling instead of chronological lists, explore CalendarJS Schedule:

  • Day, week, and weekdays views
  • Drag & drop event management
  • Resource scheduling with time slots
  • Perfect for appointment systems and team calendars

Explore CalendarJS Schedule

When to Use Each

ComponentBest ForSizeReactive
LemonadeJS TimelineReactive Vue/React/Angular apps needing data bindingPico
CalendarJS TimelineStandalone timelines, vanilla JS, non-reactive frameworks2.1KB-
CalendarJS ScheduleInteractive event scheduling with drag & drop4.2KB-

Documentation

Installation

npm install @lemonadejs/timeline

Configuration Options

Initialize the timeline with these settings to tailor the plugin to your specific needs:

AttributeDescription
data: Item[]An array of items to be displayed. Each item follows the structure defined in Entry Attributes below.
type?: 'monthly'Use 'monthly' to enable month-based filtering and the navigation header. Omit for a flat timeline.
value?: String|DateInitial date used to seed the timeline (useful with type: 'monthly'). Accepts an ISO string or a Date.
format?: StringMask used to render each item’s day label. Defaults: dd mmm yyyy (monthly), dddd, dd (otherwise).
align?: StringAlign the bullet points. Accepted values: "left", "right", "top", "bottom". Default: "left".
order?: String'asc' for ascending or 'desc' for descending. Default: 'asc'.
message?: StringDisplayed when no items match. Default: "No records found".
width?: NumberContainer width in pixels.
height?: NumberContainer height in pixels.
controls?: BooleanShow the navigation header. Defaults to true when type is 'monthly', false otherwise.
position?: StringPassthrough for the data-mode attribute on the data container; a hook for custom CSS.
url?: StringURL for fetching data.
remote?: BooleanWhen true together with url and type: 'monthly', items are refetched on month/order change.
onupdate?: FunctionCalled every time result is recomputed. Signature: (instance, result).
onedition?: FunctionCalled when the edit icon on an editable item is clicked. Signature: (entry).

Entry Attributes

Define each timeline event with these specific properties to customize its appearance and behavior:

AttributeDescription
date: String|DateThe item’s date. Required.
title: StringMain label for the item.
subtitle?: StringSecondary label shown under the title.
description?: StringLong-form description.
borderColor?: StringCSS color applied to the item’s border (--lm-border-color).
borderStyle?: StringCSS border style ("solid", "dashed", "dotted", …); sets --lm-border-style.
editable?: BooleanWhen true, renders an edit icon that fires onedition.
tags?: Tag[]Array of tag chips rendered under the description. See Tag Attributes below.

Tag Attributes

Each entry under tags accepts:

AttributeDescription
title: StringTag label.
color?: StringBackground color applied to the chip (e.g. '#dc2626', 'red').
onclick?: FunctionClick handler. Signature: (event, tag) => void.

Instance API

Calling Timeline(root, options) returns an instance exposing:

Property / MethodDescription
elThe root DOM element.
dataReactive array of items (assign to replace).
resultFiltered + sorted array used for rendering.
year / monthCurrent navigation position (month is 1-12).
monthsLocalized month names.
next() / prev()Navigate one month forward / backward.

Event Handling

Use these callbacks to monitor user interactions and to sync data with a server:

EventTrigger
onupdate?Fired after result is recomputed (initial render + every change). Signature: (instance, result).
onedition?Fired when the edit icon is clicked on an editable item. Signature: (entry).

Examples

This section illustrates practical applications of the JavaScript timeline plugin, highlighting customization techniques for style and functionality to align with specific project objectives.

See more examples on https://codesandbox.io/p/sandbox/frosty-babycat-cjcwrk

Styling Attributes

Customize the visual aspects such as position, border style, and color schemes by setting the corresponding attributes during the initialization phase as demonstrated below:

live
<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/style.min.css" />

<div id="root"></div>

<script>
const root = document.getElementById("root")

Timeline(root, {
    data: [
        {
            title: "Issue Identification",
            date: new Date(2022, 6, 1),
        },
        {
            title: "Root Cause Analysis",
            date: new Date(2022, 6, 2),
        },
        {
            title: "Implementation of Solution",
            date: new Date(2022, 6, 3),
            borderColor: '#808000',
            borderStyle: 'dashed',
        },
        {
            title: "Implementation of Solution",
            date: new Date(2022, 6, 4),
        }
    ],
    align: 'left'
})
</script>
</html>

Positioning Options

Configure the placement of the timeline on the page by choosing from four positions: left, right, bottom, or top. Adjustments can also be made programmatically, as shown in the following example:

live
<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/style.min.css" />

<label for="dropdown">Choose a position to align:</label>
<select id="dropdown">
    <option value="left">Left</option>
    <option value="right">Right</option>
    <option value="top">Top</option>
    <option value="bottom">Bottom</option>
</select>
<div id="root"></div>

<script>
const root = document.getElementById("root")
const dropdown = document.getElementById("dropdown")


const tml = Timeline(root, {
    data: [
        { title: "Issue Identification", date: new Date(2022, 6, 1) },
        { title: "Root Cause Analysis", date: new Date(2022, 6, 2) },
        { title: "Implementation of Solution", date: new Date(2022, 6, 3) },
    ],
})

dropdown.addEventListener('change', (e) => {
    tml.align = e.target.value
})
</script>
</html>

Monthly View Configuration

This setting enables a navigation control for monthly views, automatically grouping entries by their respective month and year.

live
<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/style.min.css" />
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/build/build/faker.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />

<div id="root"></div>

<script>
const root = document.getElementById("root")

let data = [];
for (let i = 0; i < 500; i++) {
    data.push({
        date: faker.date.between(new Date(2025, 1, 1), new Date(2025, 12, 30)),
        title: faker.commerce.productName(),
        subtitle: faker.commerce.department(),
        description: faker.commerce.productName(),
    })
}

const timeline = Timeline(root, {
    data: data,
    type: 'monthly',
    align: 'left',
    width: 500,
    height: 500,
})
</script>
</html>

Sorting

Configure the timeline to display events in ascending or descending chronological order.

live
<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/timeline/dist/style.min.css" />

<label for="dropdown">Choose a sorting order:</label>
<select id="dropdown-order">
    <option value="asc">Asc</option>
    <option value="desc">Desc</option>
</select>

<div id="root"></div>

<script>
const root = document.getElementById("root")
const dropdown = document.getElementById("dropdown-order")

const tml = Timeline(root, {
    data: [
        { title: "Issue Identification", date: new Date(2022, 6, 1) },
        { title: "Root Cause Analysis", date: new Date(2022, 6, 2) },
        { title: "Implementation of Solution", date: new Date(2022, 6, 3) },
    ],
})

dropdown.addEventListener('change', (e) => {
    tml.order = e.target.value;
})

</script>
</html>