e8-timeline
Updated on Sep 18, 2025 25 minutes to readA flexible and responsive timeline component for visualizing events across resources and time slots, with optional selection, drag-and-drop, and popup previews.
Overview
e8-timeline allows you to display events across multiple resources in a structured timeline.
Supports selectable ranges, draggable/resizable events, popups on hover or click, and dynamic updates.
It is fully responsive and can handle custom slot durations, headers, and time ranges.
{{ $formatter.asDate(vars.date, 'DF=MMM+D%2C+YYYY') }}
{{ event.title }}
Title: {{ event.title }}
Range {{ event.start }} - {{ event.end }}
{{ resource }}
{{ event }}
Actions
Insert this code into Main or Initialization script of the form to register a global method
E8App.$set(E8App.vars, 'date', E8App.$date.current());
E8App.$set(
E8App.vars,
'timelineResources',
[
{
id: 1,
title: 'Resource #1',
showBadges: false,
},
{
id: 2,
title: 'Resource #2',
showBadges: false,
},
{
id: 3,
title: 'Resource #3',
showBadges: false,
},
{
id: 4,
title: 'Resource #4',
showBadges: false,
},
{
id: 10,
title: 'Resource #10',
showBadges: false,
},
{
id: 11,
title: 'Resource #11',
showBadges: false,
},
{
id: 12,
title: 'Resource #12',
showBadges: false,
},
{
id: 5,
title: 'Resource #5',
showBadges: false,
},
{
id: 6,
title: 'Resource #6',
showBadges: false,
},
{
id: 7,
title: 'Resource #7',
showBadges: false,
},
{
id: 8,
title: 'Resource #8',
showBadges: false,
},
{
id: 9,
title: 'Resource #9',
showBadges: false,
},
{
id: 13,
title: 'Resource #13',
showBadges: false,
},
{
id: 14,
title: 'Resource #14',
showBadges: false,
},
{
id: 15,
title: 'Resource #15',
showBadges: false,
},
],
);
setTimeout(() => {
E8App.vars.timelineResources
.filter(() => Math.random() > 0.5)
.forEach(resource => resource.showBadges = true);
}, 3000);
const timestamp = E8App.$timestamp.startOfDay(E8App.$timestamp.current());
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const timelineEvents = [...new Array(15)].map((item, index) => {
const id = index + 1;
const resource = E8App.vars.timelineResources[getRandomInt(1, E8App.vars.timelineResources.length) - 1];
const offsetStart = getRandomInt(-5, 15);
const offsetEnd = offsetStart + getRandomInt(2, 12);
const readonly = Math.random() < 0.35;
return {
readonly,
id,
resourceId: resource.id,
title: 'Event #' + id,
description: 'Description of Event #' + id,
start: E8App.$timestamp.addHours(timestamp, offsetStart),
end: E8App.$timestamp.addHours(timestamp, offsetEnd),
textColor: !readonly ? '#007bff' : '#dc3545',
borderColor: !readonly ? '#007bff' : '#dc3545',
};
});
E8App.$set(E8App.vars, 'timelineEvents', timelineEvents);
🔽 Show more
Copy this snippet into the Content section
<e8-timeline
:initial-date="vars.date"
:resources="vars.timelineResources"
:events="vars.timelineEvents"
:show-total="true"
height="300px"
min-time="06:00:00"
max-time="22:00:00"
>
<template #resource-area-header>
<h5 class="mb-0 d-flex flex-row align-items-center">
<div class="btn-group m-0">
<button
type="button"
class="btn btn-sm btn-outline-primary"
@click="$methods.call('goToPrevDate')"
>
<e8-icon name="chevron-left"></e8-icon>
</button>
<button
type="button"
class="btn btn-sm btn-outline-primary"
@click="$methods.call('goToNextDate')"
>
<e8-icon name="chevron-right"></e8-icon>
</button>
</div>
<span class="ml-2">{{ $formatter.asDate(vars.date, 'DF=MMM+D%2C+YYYY') }}</span>
</h5>
</template>
<template #resource="{ resource }">
<div class="d-flex flex-row">
<div class="flex-grow-1">
<h5 class="m-0">
{{ resource.title }}
<span class="text-muted small ml-1">{{ resource.title }}</span>
</h5>
<template v-if="resource.showBadges">
<span class="badge badge-pill badge-primary"> {{ resource.title }} </span>
<span class="badge badge-pill badge-success"> {{ resource.title }} </span>
</template>
</div>
<div class="dropdown">
<a
class="btn btn-outline-secondary btn-sm"
href="#"
role="button"
data-toggle="dropdown"
>
<e8-icon name="three-dots-vertical"></e8-icon>
</a>
<div class="dropdown-menu">
<a
class="dropdown-item"
href="#"
>Action</a
>
<a
class="dropdown-item"
href="#"
>Another action</a
>
<a
class="dropdown-item"
href="#"
>Something else here</a
>
</div>
</div>
</div>
</template>
<template #event="{ event }">
<div class="text-muted small font-weight-bold">
<e8-icon name="clock"></e8-icon>
{{ $formatter.asTimestamp(event.start, vars.timestampTimeFormat) }} — {{ $formatter.asTimestamp(event.end,
vars.timestampTimeFormat) }}
</div>
<div class="font-weight-bold">{{ event.title }}</div>
</template>
<template #popup-title="{ event }">
<pre>Title: {{ event.title }}</pre>
</template>
<template #popup-range="{ event }">
<pre>Range {{ event.start }} - {{ event.end }}</pre>
</template>
<template #popup-description="{ resource, event }">
<pre>{{ resource }}</pre>
<pre>{{ event }}</pre>
</template>
<template #popup-actions="{ resource, event }"> Actions </template>
</e8-timeline>
🔽 Show more
Properties
| Property | Description | Type | Default |
|---|---|---|---|
| border-color-variant | Color variant of the timeline borders. | E8BorderColorVariants | — |
| events | Array of events to display on the timeline. | Array<E8TimelineEvent> | [] |
| header-durations | Durations for the header rows (can be array or object). | E8TimelineDuration | Array<E8TimelineDuration> | [{ days:1, format: SYSTEM }, { hours:1, format:SYSTEM }] |
| height | CSS height value of the timeline container. If the value is a number, it is treated as pixels (px). | string | number | auto |
| initial-date | The initial date to display on the timeline. | E8Date | — |
| max-time | Maximum time boundary for slots. | E8Time | — |
| min-time | Minimum time boundary for slots. | E8Time | — |
| minor-slot-durations | Durations for minor time slots. | E8TimelineDuration | Array<E8TimelineDuration> | { minutes:30 } |
| popup-max-width | Maximum CSS width of the popup. If the value is a number, it is treated as pixels (px). | string | number | '25rem' |
| popup-min-width | Minimum CSS width of the popup. If the value is a number, it is treated as pixels (px). | string | number | — |
| popup-on-hover | Enable popup display on hover instead of click. | boolean | false |
| resource-area-title | Title displayed above the resources area. | string | — |
| resource-area-width | Width of the resources area. | string | '25%' |
| resources | Array of resources displayed on the timeline. | Array<E8TimelineResource> | [] |
| readonly | Disables editing, dragging, and resizing of events. | boolean | false |
| selectable | Enable selecting a range of time slots. | boolean | true |
| selection-color-variant | Color variant for selected slots. | E8BackgroundColorVariants | 'light' |
| slot-duration | Duration of each main time slot. | E8TimelineDuration | { minutes:30 } |
| slot-width | Width of each time slot in pixels. | number | '30px' |
| show-total | Show the total area column. | boolean | false |
| total-area-title | Title for the total area column. | string | — |
| total-area-width | CSS width of the total area column. If the value is a number, it is treated as pixels (px). | string | number | '75px' |
| view-duration | Duration to display on the timeline (e.g., 1 day, 1 week). | E8TimelineDuration | { days:1 } |
Slots
| Slot | Description |
|---|---|
| default | Container for timeline content; timeline renders resources and events. |
| event | Slot for each event; receives event as parameter. |
| popup-actions | Custom actions inside the popup (e.g., buttons). |
| popup-description | Custom content for the popup description. |
| popup-range | Custom content showing the range of the event. |
| popup-title | Custom content for the popup title. |
| resource | Slot for each resource; receives resource as parameter. |
| resource-area-header | Custom content above the resources area. |
| total | Custom content for the total column cells. |
| total-area-header | Custom content above the total area column. |
Events
| Event | Description |
|---|---|
| on-change-event | Triggered when an event is changed. |
| on-change-period | Triggered when the visible timeline period changes. |
| on-delete-event | Triggered when an event is deleted. |
| on-drop-event | Triggered when an event is dropped to a new slot. |
| on-edit-event | Triggered when an event is edited. |
| on-resize-event | Triggered when an event is resized. |
| on-select-range | Triggered when a time range is selected. |