Vanilla Timeline (Vantl) is a lightweight, responsive timeline library created with vanilla Javascript for creating beautiful horizontal and vertical timelines with zero dependencies. Inspired by timeline originally created by squarechip in 2018. You can load your timeline data via a variety of methods and, you can include multiple timelines on a single page.
- β¨ Zero dependencies - Pure vanilla JavaScript (jQuery optional)
- π± Fully responsive - Auto-switches between horizontal/vertical layouts
- π¨ Customizable colors - Theme nodes, lines, and navigation
- πΌοΈ Rich content - Support for images, HTML, and modal popups
- π Deep linking - Link directly to specific timeline nodes via URL
- π¦ Multiple layouts - Vertical scroll or horizontal carousel modes
- πΎ Smart caching - LocalStorage caching for JSON data
- π Auto-init - Just add a data attribute to load from JSON
- π Small footprint - Minified and tree-shakeable
Load stylesheet and Javascript functions to your document via CDN links:
<!DOCTYPE html>
<html>
<head>
<!-- load stylesheet -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kendawson-online/vantl@latest/dist/timeline.min.css">
</head>
<body>
<!-- your timeline will go here -->
<!-- load functions -->
<script src="https://cdn.jsdelivr.net/npm/@kendawson-online/vantl@latest/dist/timeline.min.js"></script>
</body>
</html>Add some timeline node data in HTML. If you want your timeline to be oriented horizontally, set data-mode="horizontal" on the parent element (see code below). If you omit this setting, the timeline will be oriented vertically by default.
<!-- your timeline -->
<div class="timeline" data-mode="horizontal">
<div class="timeline__wrap">
<div class="timeline__items">
<div class="timeline__item">
<div class="timeline__content">
<h5>Jan. 1, 2000</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum.</p>
</div>
</div>
<div class="timeline__item">
<div class="timeline__content">
<h5>Dec. 31, 2000</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum.</p>
</div>
</div>
<div class="timeline__item">
<div class="timeline__content">
<h5>Jan. 1, 2001</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum.</p>
</div>
</div>
</div>
</div>
</div>Add one line of code at the bottom to initialize your timeline. It goes after the CDN link but before the closing </body> tag and looks like this:
<!-- load functions -->
<script src="https://cdn.jsdelivr.net/npm/@kendawson-online/vantl@latest/dist/timeline.min.js"></script>
<!-- initialize the timeline -->
<script>
timeline(document.querySelectorAll('.timeline'));
</script>
</body>
</html>Note: if you're using jQuery in your document, you can initialize your timeline like this:
<!-- load functions -->
<script src="https://cdn.jsdelivr.net/npm/@kendawson-online/vantl@latest/dist/timeline.min.js"></script>
<!-- initialize timeline with jQuery -->
<script>
jQuery(function () {
$('.timeline').timeline({
mode: 'horizontal'
});
});
</script>
</body>
</html>For more info check the Advanced Usage section below
You can add data attributes to the timeline element to control how it looks and/or functions. For example, this is how you would set the orientation of the timeline to be horizontal instead of vertical (default):
<div class="timeline" data-mode="horizontal">
...
</div> If you don't pass an attribute, the app will simply use the default values.
Here are the available data attributes:
| Option | Type | Default | Description |
|---|---|---|---|
data-mode |
string | 'vertical' |
Layout mode: 'vertical' or 'horizontal' |
data-min-width |
number | 600 |
Minimum viewport width (px) to maintain horizontal mode |
data-max-width |
number | 600 |
Maximum viewport width (px) to maintain vertical mode |
data-move-items |
number | 1 |
Items to scroll per navigation click (horizontal) |
data-start-index |
number | 0 |
Initial item index (horizontal mode) |
data-horizontal-start-position |
string | 'top' |
First item alignment in horizontal layout: 'top' or 'bottom' |
data-vertical-start-position |
string | 'left' |
First item alignment in vertical layout: 'left' or 'right' |
data-same-side-nodes |
string | boolean | false |
data-vertical-trigger |
string | '15%' |
Scroll trigger distance: percentage or px (e.g., '20%' or '150px') |
data-rtl-mode |
boolean | false |
Right to left mode: true or false (only works in horizontal mode and overrides startIndex setting) |
data-node-color |
string | β | Node circle color (hex/rgb/hsl) |
data-line-color |
string | β | Timeline line color (hex/rgb/hsl) |
data-nav-color |
string | β | Navigation button color (hex/rgb/hsl) |
data-json-config |
string | β | path to a JSON data file (e.g., /path/to/valid/file.json) |
See the API Documentation for a more detailed description of all options.
A great way to use Vanilla Timeline is to store and load your data from an external JSON file. JSON stands for: "JavaScript Object Notation".
It's a lightweight text format stored in a file with a .json extension. It's easy for humans to read and write and for machines to parse and use in apps. JSON is based on a web standard so you have to follow the rules to produce "well-formed JSON" that is formatted a specific way. A simple JSON file might look something like this:
{
"timelineName": "Timeline Title",
"layoutMode": "horizontal",
"minWidth": 700,
"maxWidth": "",
"nodeColor": "",
"lineColor": "",
"navColor": ""
}To use JSON, you add a data attribute called data-json-config to your HTML to tell the app which JSON file you want to load:
<div class="timeline" data-json-config="/path/to/timeline.json"></div>data-json-config value, the app will prioritize JSON file settings and ignore any other data attribute values being passed inline via HTML.
If you load your timeline data using the JSON method, you don't have to add the extra line of code at the bottom of the page (used to initialize the timeline). When a JSON file is loaded, the app is initialized automatically.
Here are some examples of JSON files you can use as templates to build your own timelines:
ποΈ A NOTE ABOUT DATES IN JSON ποΈ
Dates stored in JSON data files (e.g. the lastupdated field) are stored in a special format called ISO 8601. The vanilla timeline app expects dates to be in this specific format.
There is a demo page which displays dates in this format for you. The page also teaches you how to generate ISO 8601 timestamps in the developer console of your own web browser. Open the demo/time.html file in a browser to see a current ISO 8601 timestamp. You can copy/paste this date string directly to your JSON timelines.
Link to a specific timeline node using URL parameters:
https://example.com/page.html?timeline=myTimelineId&id=3
https://[domain name]/[page name]?timeline=[timeline ID]&id=[node id]
- Add an
idattribute and value to your timeline container:
<div id="myTimeline" class="timeline">
...
</div> - Add a
data-node-idto each node you want to link to
<div class="timeline__items">
<!-- node 1 -->
<div class="timeline__item" data-node-id="1">
<div class="timeline__content">
<h5>Jan. 1, 2015</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore.</p>
</div>
</div>
<!-- node 2 -->
<div class="timeline__item" data-node-id="2">
<div class="timeline__content">
<h5>Dec. 31, 2016</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore.</p>
</div>
</div>
</div> Note: you can also add an id attribute directly like so:
<div class="timeline__items">
<!-- node 1 -->
<div class="timeline__item" id="1">
<div class="timeline__content">
<h5>Jan. 1, 2015</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore.</p>
</div>
</div>
<!-- node 2 -->
<div class="timeline__item" id="2">
<div class="timeline__content">
<h5>Dec. 31, 2016</h5>
<p>Lorem ipsum dolor sit amet, qui minim labore.</p>
</div>
</div>
</div> Deep linking works automatically with JSON-loaded timelines
npm install @kendawson-online/vantlImporting timeline functions into your Javscript app:
import { timeline } from '@kendawson-online/vantl';
import '@kendawson-online/vantl/dist/timeline.min.css';
timeline(document.querySelectorAll('.timeline'), {
mode: 'vertical',
nodeColor: '#2d6cdf'
});// vanilla Javascript
timeline(document.querySelectorAll('.timeline'), {
mode: 'horizontal'
});
// jQuery
$('.timeline').timeline({
mode: 'vertical',
verticalTrigger: '20%'
});All options can be set via JavaScript API, data attributes, or with JSON config.
| Option | Type | Default | Description |
|---|---|---|---|
mode |
string | 'vertical' |
Layout mode: 'vertical' or 'horizontal' |
minWidth |
number | 600 |
Min viewport width (px) to maintain horizontal mode |
maxWidth |
number | 600 |
Max viewport width (px) to maintain vertical mode |
moveItems |
number | 1 |
Items to scroll per navigation click (horizontal) |
startIndex |
number | 0 |
Initial item index (horizontal mode) |
horizontalStartPosition |
string | 'top' |
First item alignment: 'top' or 'bottom' |
verticalStartPosition |
string | 'left' |
First item alignment: 'left' or 'right' |
sameSideNodes |
string | boolean | false |
verticalTrigger |
string | '15%' |
Scroll trigger distance: percentage or px (e.g., '20%' or '150px') |
rtlMode |
boolean | false |
Right-to-left mode (horizontal) |
nodeColor |
string | β | Node circle color (hex/rgb/hsl) |
lineColor |
string | β | Center line color (hex/rgb/hsl) |
navColor |
string | β | Navigation button color (hex/rgb/hsl) |
Override the auto-detected image path:
<script>
window.TimelineConfig = {
basePath: '/custom/path/to/images'
};
</script>
<script src="dist/timeline.min.js"></script>// Load from JSON programmatically
loadDataFromJson('/data/timeline.json', '#myTimeline');
// Clear cache
clearTimelineCache(); // Clear all cached JSON timelines
clearTimelineCache('/data/my-timeline.json'); // Clear cache for specific JSON URL
// Navigate to node (horizontal mode)
navigateTimelineToNodeIndex(containerElement, 5);
// Open modal
openTimelineModal(itemElement);
// Close modal
closeTimelineModal();- SwiperJS is a third-party library; Vantl only ships an adapter. You must bring Swiper yourself and consult the Swiper docs for setup and features.
- Resolution order when
useSwiperis enabled:options.swiperCdn(ESM URL) β installedswiperpackage (dynamic import) βwindow.Swiperfrom a UMD CDN. If none are found, Vanilla Timeline falls back to its built-in carousel controls. - Enable with
data-use-swiper="true"(or booleantrue) in HTML oruseSwiper: 'true' | 'auto' | truein JS. Pass Swiper options viaswiperOptions. - Build warning about unresolved
swiperis expected when you have not installed it; either ignore, mark it external (e.g.,external: ['swiper']), or install Swiper to silence the warning.
UMD CDN example (provides window.Swiper):
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@12.4.7/swiper-bundle.min.css">
<script src="https://cdn.jsdelivr.net/npm/swiper@12.4.7/swiper-bundle.min.js"></script>
<script src="dist/timeline.min.js"></script>
<script>
timeline(document.querySelectorAll('.timeline'), { useSwiper: 'auto' });
// Swiper-specific options: { swiperOptions: { loop: true } }
</script>- Chrome/Edge (2018+)
- Firefox (2018+)
- Safari (2018+)
- Requires: ES6, IntersectionObserver, CSS Custom Properties
See Development.md for build instructions and an architectural overview.
See API Documentation for details about how the API works.
You can report issues and open pull requests on GitHub:
NPM Package: @kendawson-online/vantl
Repository: github.com/kendawson-online/vantl
CDN: cdn.jsdelivr.net/npm/@kendawson-online/vantl
Originally inspired by timeline by Mike Collins (2018).
Refactored and maintained by Ken Dawson (2026).

