React Chrono
A flexible and modern timeline component for React.
React Chrono is a modern timeline component for React that offers a variety of features and customization options. It allows you to render timelines in horizontal, vertical, and vertical-alternating modes, display images and videos, and much more.
Table of Contents
β¨ Features
- π₯ Multiple Modes: Render timelines in Horizontal, Vertical, or Vertical-Alternating layouts.
- πΊ Slideshow: Auto-play the timeline with slideshow functionality.
- πΌοΈ Media Support: Easily display images and videos within timeline cards.
- β¨οΈ Keyboard Accessible: Navigate the timeline using keyboard controls.
- π§ Custom Content: Render custom React components within timeline cards.
- πΏ Nested Timelines: Display timelines within timeline cards for complex narratives.
- β‘ Data-Driven API: Configure the timeline dynamically using a simple data structure.
- π¨ Theming: Customize colors and appearance with ease.
- π Custom Icons: Use your own icons for timeline points.
- πͺ TypeScript: Built with TypeScript for robust development.
- π
Styled with Styled Component: Leverages Styled Component for flexible styling.
πΎ Installation
yarn add react-chrono
npm install react-chrono
π Getting Started
Ensure you wrap the Chrono
component in a container with a specified width
and height
.
Basic Horizontal Mode
By default, if no mode
is specified, the component renders in HORIZONTAL
mode.
import React from "react";
import { Chrono } from "react-chrono";
const App = () => {
const items = [
{
title: "May 1940",
cardTitle: "Dunkirk",
url: "http://www.history.com",
cardSubtitle: "Men of the British Expeditionary Force (BEF) wade out to a destroyer...",
cardDetailedText: "Men of the British Expeditionary Force (BEF) wade out to a destroyer during the evacuation from Dunkirk.",
media: {
type: "IMAGE",
source: {
url: "http://someurl/image.jpg"
}
}
},
];
return (
<div style={{ width: "800px", height: "400px" }}>
<Chrono items={items} />
</div>
);
};
export default App;

Vertical Mode
To render the timeline vertically, set the mode
prop to VERTICAL
.
<div style={{ width: '300px', height: '950px' }}>
<Chrono items={items} mode="VERTICAL" />
</div>

Vertical Alternating Mode
For a layout where cards alternate sides, use VERTICAL_ALTERNATING
.
<div style={{ width: '500px', height: '950px' }}>
<Chrono items={items} mode="VERTICAL_ALTERNATING" />
</div>

βοΈ Props
React Chrono offers a wide range of props for customization.
Core Props
items | TimelineItemModel[] | [] | An array of Timeline Item objects to display. |
mode | 'HORIZONTAL' , 'VERTICAL' , 'VERTICAL_ALTERNATING' | 'HORIZONTAL' | Sets the layout mode of the timeline. Changed to HORIZONTAL from VERTICAL_ALTERNATING for new projects. |
theme | Theme | {...} | Customizes colors. See Theming & Styling for details. |
Timeline Item Model
Each object in the items
array can have the following properties:
title | string | Title of the timeline item (often a date or short label). |
cardTitle | string | Title displayed on the timeline card. |
cardSubtitle | string | Subtitle text displayed on the timeline card. |
cardDetailedText | string or string[] | Detailed text for the card. An array of strings will render each string as a separate paragraph. |
media | TimelineMediaModel | Object to configure image or video display. See Media Handling. |
url | string | URL associated with the timeline item's title. Clicking the title will navigate to this URL. |
date | Date or string | Date to be used in the title. If provided, this will override the title property for display purposes. |
timelineContent | ReactNode | Custom React content to render inside the card. Overrides cardDetailedText . See Rendering Custom Content. |
items | TimelineItemModel[] | Array of timeline items for creating Nested Timelines. |
active | boolean | If true, this item will be initially active (only for the first matching item). |
id | string | A unique identifier for the timeline item. |
visible | boolean | Controls the visibility of the timeline item. |
Example TimelineItemModel
:
{
title: "May 1940",
cardTitle: "Dunkirk",
cardSubtitle: "Evacuation of Allied soldiers from the beaches and harbour of Dunkirk, France.",
cardDetailedText: ["Paragraph one about Dunkirk.", "Paragraph two providing more details."],
media: {
type: "IMAGE",
source: {
url: "http://someurl/dunkirk.jpg"
},
name: "Dunkirk Evacuation"
},
url: "https://en.wikipedia.org/wiki/Dunkirk_evacuation",
}
Navigation & Interaction
activeItemIndex | number | 0 | Index of the timeline item to be active on load. |
disableNavOnKey | boolean | false | Disables keyboard navigation (LEFT/RIGHT for Horizontal, UP/DOWN for Vertical). |
disableClickOnCircle | boolean | false | Disables click action on timeline points/circles. |
disableAutoScrollOnClick | boolean | false | Prevents auto-scrolling to the active card when a timeline card or point is clicked. |
onItemSelected | function | | Callback function invoked when a timeline item is selected. Passes item data and index. |
onScrollEnd | function | | Callback function invoked when the end of the timeline is reached during scrolling. |
focusActiveItemOnLoad | boolean | true | Automatically scrolls to and focuses on the activeItemIndex when the timeline loads. |
disableInteraction | boolean | false | Disables all user interactions with the timeline (clicks, keyboard navigation). |
enableQuickJump | boolean | true | Allows quick jumping to a timeline item via controls (if toolbar is enabled). |
useReadMore | boolean | true | Enables a "read more" button if card content exceeds available space. Set to false to always show all text. |
Keyboard Navigation:
- Horizontal Mode: Use LEFT and RIGHT arrow keys.
- Vertical/Vertical Alternating Mode: Use UP and DOWN arrow keys.
- HOME: Jump to the first item.
- END: Jump to the last item.
Layout & Sizing
cardHeight | number | 200 | Minimum height (in pixels) of timeline cards. |
cardWidth | number | 450 | Maximum width (in pixels) of timeline cards. |
itemWidth | number | 300 | Width (in pixels) of each timeline section in HORIZONTAL mode. |
contentDetailsHeight | number | 150 | Height (in pixels) of the detailed content area within a card if cardDetailedText is used. |
lineWidth | number | 3 | Width (in pixels) of the main timeline track line. |
timelinePointDimension | number | 16 | Diameter (in pixels) of the circular points on the timeline. |
nestedCardHeight | number | 150 | Height (in pixels) of cards within a nested timeline. |
scrollable | boolean or { scrollbar: boolean } | true | Makes VERTICAL and VERTICAL_ALTERNATING modes scrollable. Set to { scrollbar: true } to show the scrollbar. |
enableBreakPoint | boolean | true | If true, VERTICAL_ALTERNATING mode automatically switches to VERTICAL mode when responsiveBreakPoint is reached. |
responsiveBreakPoint | number | 768 | Viewport width (in pixels) at which VERTICAL_ALTERNATING mode switches to VERTICAL if enableBreakPoint is true. Default changed to 768 . |
cardPositionHorizontal | 'TOP' or 'BOTTOM' | 'BOTTOM' | Positions the card above or below the timeline in HORIZONTAL mode. Default changed to 'BOTTOM' . |
flipLayout | boolean | false | Reverses the layout direction (e.g., Right-to-Left for horizontal, or swaps sides for vertical alternating). |
showAllCardsHorizontal | boolean | false | In HORIZONTAL mode, displays all cards simultaneously instead of only the active one. |
Media Handling
The media
object within a Timeline Item configures images or videos.
type | 'IMAGE' or 'VIDEO' | Specifies the type of media. |
source | { url: string, type?: string } | url : URL of the image or video. type (for video): e.g., 'mp4' , 'webm' . |
name | string | Alt text for images or a descriptive name for videos. |
active | boolean | (Video only) If true, video will attempt to play when its card becomes active. |
id | string | A unique ID for the media element. |
videoOptions | HTMLVideoElement attributes | (Video only) An object containing standard HTML5 video attributes like loop , muted , autoPlay , etc. |
Image Example:
media: {
type: "IMAGE",
name: "dunkirk beach",
source: {
url: "http://someurl/image.jpg"
}
}
Video Example (auto-plays when active, muted):
media: {
type: "VIDEO",
name: "Pearl Harbor",
source: {
url: "/pearl-harbor.mp4",
type: "mp4"
},
videoOptions: { autoPlay: true, muted: true }
}

Media Settings Prop (mediaSettings
):
This top-level prop on <Chrono>
controls global media display:
align | 'left' , 'right' , 'center' | 'left' | Alignment of media within the card. Default changed to 'left' . |
fit | 'cover' , 'contain' , 'fill' , 'none' , 'scale-down' | 'cover' | CSS object-fit property for images. |
<Chrono items={items} mediaSettings={{ align: 'right', fit: 'contain' }} />
Content & Display
borderLessCards | boolean | false | Removes borders and shadows from timeline cards for a flatter look. |
cardLess | boolean | false | Hides timeline cards, showing only titles/points. Useful for a very compact timeline. |
disableTimelinePoint | boolean | false | Hides the circular points on the timeline track. |
timelinePointShape | 'circle' , 'square' , 'diamond' | 'circle' | Configures the shape of the points on the timeline. |
textOverlay | boolean | false | Displays text content as an overlay on top of media elements. Requires text property in timeline items. |
parseDetailsAsHTML | boolean | false | If true, cardDetailedText will be parsed as HTML. Use with caution due to XSS risks if content is user-supplied. |
titleDateFormat | string | 'MMM DD, YYYY' | Date format for item titles when using the date property in items. Supports all day.js formats. |
textDensity | 'LOW' or 'HIGH' | 'HIGH' | Configures the amount of text displayed in cards. 'LOW' might truncate more aggressively. |
Text Overlay Mode:
Enable textOverlay
and provide a text
property in your items
.
const items = [
{
title: 'First item',
media: { type: 'IMAGE', source: { url: 'https://example.com/image.jpg' }},
text: 'This is the caption for the first item, appearing over the image.'
}
];
<Chrono items={items} textOverlay />;

Theming & Styling
Use the theme
prop to customize colors:
<Chrono
items={items}
theme={{
primary: 'red',
secondary: 'blue',
cardBgColor: 'yellow',
cardForeColor: 'black',
titleColor: 'black',
titleColorActive: 'red',
}}
/>
For a complete list of themeable properties, please refer to the Theme
type definition in the source code or Storybook examples.
Dark Mode Toggle:
enableDarkToggle | boolean | false | Adds a toggle switch to the toolbar for enabling dark mode (if dark theme is configured). |
onThemeChange | function | | Callback invoked when the theme changes, e.g., via the dark mode toggle. Passes the new theme object. |
Slideshow
slideShow | boolean | false | Enables slideshow mode and shows play/pause controls in the toolbar. |
slideItemDuration | number | 2000 | Duration (in milliseconds) each timeline item remains active during a slideshow. Default changed to 2000 . |
slideShowType | 'reveal' , 'slide_from_sides' , 'slide_in' | Varies by mode | Type of animation for slideshow transitions. Defaults: VERTICAL -> 'reveal' , VERTICAL_ALTERNATING -> 'slide_from_sides' , HORIZONTAL -> 'slide_in' . |
<Chrono items={items} slideShow slideItemDuration={3000} />
Slideshow can be stopped by clicking the stop button or pressing ESC.
Search
searchPlaceholder | string | "Search..." | Placeholder text for the search input in the toolbar. |
searchAriaLabel | string | "Search timeline" | ARIA label for the search input for accessibility. |
clearSearch | string | "Clear search" | Text/ARIA label for the clear search button. |
<Chrono
items={data}
searchPlaceholder="Find in timeline..."
/>
Search functionality is part of the toolbar. To hide search (and the toolbar), set disableToolbar={true}
.
Miscellaneous
allowDynamicUpdate | boolean | false | Enables dynamic updates of timeline items. If true, changes to the items prop will re-render the timeline. |
noUniqueId | boolean | false | Prevents generating a unique ID for the timeline wrapper. Use with uniqueId if you need to set a specific ID. |
uniqueId | string | | Sets a custom unique ID for the timeline wrapper. Useful with noUniqueId={true} . |
disableToolbar | boolean | false | Hides the entire toolbar/control panel. |
toolbarPosition | 'TOP' or 'BOTTOM' | 'TOP' | Positions the toolbar at the top or bottom of the timeline. |
highlightCardsOnHover | boolean | false | Highlights timeline cards on mouse hover. |
π¨ Customization
Rendering Custom Content
Pass React elements as children to <Chrono>
. Each child will be rendered into a timeline card. This can be combined with the items
prop to provide titles or other metadata.
const customItems = [
{ title: '2023-01-01', cardTitle: 'Event One' },
{ title: '2023-02-15', cardTitle: 'Event Two' },
];
<Chrono mode="VERTICAL" items={customItems}>
<div>
<h4>Custom Content for Event One</h4>
<p>This is fully custom JSX rendered in the first card.</p>
</div>
<div>
<img src="<url_to_image>" alt="Custom Image" style={{width: "100%"}} />
<p>An image in the second card.</p>
</div>
</Chrono>
Custom Icons
Provide images for timeline points by wrapping them in a div
with className="chrono-icons"
as a child of <Chrono>
. Icons are applied sequentially.
<Chrono items={items} mode="VERTICAL_ALTERNATING">
{}
<div>Card 1 Content</div>
<div>Card 2 Content</div>
{}
<div className="chrono-icons">
<img src="image1.svg" alt="icon1" />
<img src="image2.svg" alt="icon2" />
{}
</div>
</Chrono>
Nested Timelines
Create timelines within timeline cards by providing an items
array within a parent timeline item.
const itemsWithNested = [
{
title: 'Main Event 1',
cardTitle: 'Chapter 1',
items: [
{ cardTitle: 'Sub-event 1.1', cardSubtitle: 'Details for 1.1' },
{ cardTitle: 'Sub-event 1.2', media: { type: "IMAGE", source: { url: '...' } } },
],
},
{ title: 'Main Event 2', cardTitle: 'Chapter 2' },
];
<Chrono mode="VERTICAL" items={itemsWithNested} nestedCardHeight={120} />
Custom Class Names
Apply your own CSS classes to various parts of the timeline using the classNames
prop.
<Chrono
items={items}
classNames={{
card: 'my-custom-card',
cardMedia: 'my-card-media',
cardSubTitle: 'my-card-subtitle',
cardText: 'my-card-text',
cardTitle: 'my-card-title',
controls: 'my-timeline-controls',
title: 'my-timeline-title',
timelinePoint: 'my-timeline-point',
timelineTrack: 'my-timeline-track',
}}
/>
Custom Font Sizes
Adjust font sizes for card elements using the fontSizes
prop.
<Chrono
items={data}
fontSizes={{
cardSubtitle: '0.85rem',
cardText: '0.8rem',
cardTitle: '1.1rem',
title: '0.9rem',
}}
/>
Custom Button Alt Text
Customize the alt
text for toolbar navigation buttons via buttonTexts
.
<Chrono
items={data}
buttonTexts={{
first: 'Jump to First Item',
last: 'Jump to Last Item',
next: 'View Next Item',
previous: 'View Previous Item',
play: 'Start Slideshow',
stop: 'Stop Slideshow',
jumpTo: 'Jump to specific item'
}}
/>
Default buttonTexts
values:
first | 'Go to First' |
last | 'Go to Last' |
next | 'Next' |
previous | 'Previous' |
play | 'Play Slideshow' |
stop | 'Stop Slideshow' |
jumpTo | 'Jump to' |
π¦ Examples & Demos
CodeSandbox Examples
Explore various configurations of React Chrono:
Kitchen Sink Demo
See a comprehensive demo showcasing many features:
Storybook
Dive into a wide variety of examples hosted on Storybook:
π οΈ Build Setup
pnpm install
pnpm dev
pnpm lint:css
pnpm eslint
pnpm lint
pnpm rollup
π§ͺ Tests
pnpm test
pnpm cypress:test
pnpm cypress:headless
pnpm cypress:quiet
π€ Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create your feature branch (
git checkout -b new-feature
).
- Commit your changes (
git commit -am 'Add: New amazing feature'
).
- Push to the branch (
git push origin new-feature
).
- Create a new Pull Request.
Please read CONTRIBUTING.md
for more details on the process and CODE_OF_CONDUCT.md
.
π§± Built With
π Support & Meta
Special thanks to BrowserStack for providing an Open Source License for testing.
Distributed under the MIT license. See LICENSE
for more information.
Prabhu Murthy β @prabhumurthy2 β prabhu.m.murthy@gmail.com
GitHub: https://github.com/prabhuignoto


β¨ Contributors
Thanks to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind are welcome!