
Syncfusion React Timeline
- 337 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
Use syncfusion-react-timeline for development tasks
About
syncfusion-react-timeline: A skill for development. This provides functionality for development workflows.
- syncfusion-react-timeline
Syncfusion React Timeline by the numbers
- 337 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,193 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-timelineAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 337 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
What it does
Use syncfusion-react-timeline for development tasks
Files
Implementing Syncfusion React Timeline
The Timeline component displays events or steps in chronological order with visual indicators. It supports vertical and horizontal layouts, multiple alignment modes, customizable dots and connectors, templates, and events for complete flexibility.
When to Use This Skill
Use the Timeline component when:
- Displaying event sequences chronologically (project milestones, shipping tracking, activity logs)
- Creating career progression or timeline visualizations
- Building step-by-step process flows
- Showing company history or project roadmap
- Implementing event feeds with timestamps
- Displaying before/after comparisons in alternate layouts
- Customizing visual indicators (icons, images, colors) for events
Choose Timeline over alternatives:
- vs Stepper: Timeline shows completed events; Stepper guides users through steps
- vs List: Timeline emphasizes chronological relationships and connections
- vs Chart: Timeline focuses on event sequence; Chart focuses on data relationships
Quick Start Example
import { TimelineComponent, ItemsDirective, ItemDirective } from '@syncfusion/ej2-react-layouts';
import '@syncfusion/ej2-base/styles/tailwind3.css';
import '@syncfusion/ej2-layouts/styles/tailwind3.css';
function App() {
return (
<div style={{ height: '350px' }}>
<TimelineComponent>
<ItemsDirective>
<ItemDirective content="Shipped" />
<ItemDirective content="Departed" />
<ItemDirective content="Arrived" />
<ItemDirective content="Out for Delivery" />
</ItemsDirective>
</TimelineComponent>
</div>
);
}
export default App;Component Overview
TimelineComponent is the root container that manages the timeline layout and behavior.
Key Properties:
orientation: Layout direction (Vertical|Horizontal)align: Content positioning (Before|After|Alternate|AlternateReverse)reverse: Invert display order (most recent first)cssClass: Apply custom stylestemplate: Custom rendering for timeline items
ItemsDirective & ItemDirective define timeline items within the component.
Item Properties:
content: Main event text or templateoppositeContent: Secondary text on opposite sidedotCss: CSS class for dot styling (icons, images, custom appearance)cssClass: Individual item stylingdisabled: Disable interaction and dim appearance
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation via npm and package dependencies
- CSS imports and theme setup
- Basic TimelineComponent structure
- ItemsDirective and ItemDirective usage
- Running your first timeline application
Layout Configuration
📄 Read: references/layout-configuration.md
- Orientation options (Vertical, Horizontal)
- Alignment modes (Before, After, Alternate, AlternateReverse)
- Content positioning strategies
- Choosing the right layout for your use case
- Code examples for each layout combination
Items and Content
📄 Read: references/items-and-content.md
- Adding string content
- Template-based rich content
- Opposite content configuration
- Dot customization with icons, images, and text
- Disabling individual items
- Per-item CSS classes
Styling and Customization
📄 Read: references/styling-and-customization.md
- Connector styling (common and per-item)
- Dot color, size, shadow, outline, and variants
- CSS custom properties for dots
- e-outline class usage
- Complete customization examples
Events and Callbacks
📄 Read: references/events-and-callbacks.md
createdevent when component rendersbeforeItemRenderevent for item customization- Event handling patterns and use cases
Advanced Features
📄 Read: references/advanced-features.md
- Template property for complete custom rendering
- Template context (item, itemIndex)
- Reverse property for newest-first display
- Complex template patterns
- When to use templates vs built-in properties
Accessibility
📄 Read: references/accessibility.md
- WCAG 2.2 and Section 508 compliance
- ARIA attributes and roles
- Keyboard navigation support
- RTL (Right-to-Left) language support
- Mobile device accessibility
Common Patterns
Pattern 1: Vertical Timeline with Before Alignment
<TimelineComponent orientation='Vertical' align='Before'>
<ItemsDirective>
<ItemDirective content='Step 1' oppositeContent='Description' />
<ItemDirective content='Step 2' oppositeContent='Description' />
</ItemsDirective>
</TimelineComponent>Pattern 2: Horizontal Alternate Layout
<TimelineComponent orientation='Horizontal' align='Alternate'>
<ItemsDirective>
<ItemDirective content='Event 1' oppositeContent='Date 1' />
<ItemDirective content='Event 2' oppositeContent='Date 2' />
</ItemsDirective>
</TimelineComponent>Pattern 3: Timeline with Custom Dots and Icons
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Shipped' dotCss='e-icons e-package' />
<ItemDirective content='Delivered' dotCss='e-icons e-check' cssClass='state-completed' />
</ItemsDirective>
</TimelineComponent>Pattern 4: Activity Feed with Reverse Order
<TimelineComponent reverse={true}>
<ItemsDirective>
<ItemDirective content='Latest activity' />
<ItemDirective content='Previous activity' />
</ItemsDirective>
</TimelineComponent>Key Props Summary
| Prop | Type | Values | Purpose |
|---|---|---|---|
orientation | string | Vertical (default), Horizontal | Layout direction |
align | string | Before, After, Alternate, AlternateReverse | Content positioning |
reverse | boolean | true, false (default) | Reverse item order |
cssClass | string | CSS class name | Global styling |
template | function | React function | Custom item rendering |
content (item) | string \ | function | Text or template |
oppositeContent (item) | string \ | function | Text or template |
dotCss (item) | string | CSS class | Dot styling |
disabled (item) | boolean | true, false | Disable item |
cssClass (item) | string | CSS class | Per-item styling |
Troubleshooting
Timeline not displaying:
- Ensure CSS imports are included (tailwind3.css or your theme)
- Container must have explicit height:
style={{ height: '350px' }} - ItemsDirective must contain ItemDirective children
Items not centered vertically:
- Add
heightto TimelineComponent container - Adjust with CSS custom properties:
--dot-size,--dot-outer-space
Content positioning unexpected:
- Verify
alignproperty:Before,After,Alternate,AlternateReverse - Check
oppositeContentis defined for two-sided layouts - Confirm
orientationmatches your layout intent
Dots not visible:
- Verify dots have
e-outlineclass or custom CSS styling - Check
dotCssproperty contains valid CSS class names - Ensure theme CSS includes dot styles
Templates not rendering:
- Verify template function returns valid JSX
- Check context properties:
props.item,props.itemIndex - Ensure function signature matches:
(props: any) => JSX.Element
Accessibility
Table of Contents
- Compliance Standards
- ARIA Attributes
- Keyboard Navigation
- Screen Reader Support
- Color Contrast
- Right-to-Left (RTL) Support
- Mobile Device Accessibility
- Accessibility Best Practices Checklist
- Accessibility Testing
- Resources
Compliance Standards
The Timeline component meets major accessibility standards:
| Standard | Support | Details |
|---|---|---|
| WCAG 2.2 | ✅ Full | Web Content Accessibility Guidelines Level AA compliance |
| Section 508 | ✅ Full | U.S. federal accessibility requirement |
| Right-to-Left (RTL) | ✅ Full | Bidirectional text and layout support |
| Mobile Device Support | ✅ Full | Touch-friendly interactions and responsive design |
| Color Contrast | ✅ Full | WCAG AA minimum contrast ratios (4.5:1 for text) |
| Accessibility Checker | ✅ Validated | Tested with automated accessibility tools |
| Axe-core | ✅ Validated | Automated accessibility testing suite |
ARIA Attributes
The Timeline component uses WAI-ARIA attributes to communicate semantic meaning to screen readers.
Navigation Role
<TimelineComponent role="navigation">
<ItemsDirective>
<ItemDirective content="Event 1" />
<ItemDirective content="Event 2" />
</ItemsDirective>
</TimelineComponent>Role: navigation - Identifies the component as a navigational element.
ARIA Labels
// Add accessible label to container
<div id="timeline-container" role="region" aria-label="Project Timeline">
<TimelineComponent>
<ItemsDirective>
<ItemDirective content="Phase 1" aria-label="Phase 1: Planning" />
<ItemDirective content="Phase 2" aria-label="Phase 2: Development" />
</ItemsDirective>
</TimelineComponent>
</div>aria-label: Provides accessible name when visible text isn't clear.
Semantic HTML
Use semantic HTML to enhance accessibility:
<section aria-labelledby="timeline-title">
<h2 id="timeline-title">Project Milestones</h2>
<TimelineComponent role="list">
<ItemsDirective>
<ItemDirective role="listitem" content="Milestone 1" />
<ItemDirective role="listitem" content="Milestone 2" />
</ItemsDirective>
</TimelineComponent>
</section>Keyboard Navigation
Timeline components support keyboard interaction for users who cannot use a mouse.
Keyboard Support
- Tab: Navigate between timeline items
- Shift+Tab: Navigate backwards through items
- Enter/Space: Activate interactive elements
Implementing Keyboard Navigation
function AccessibleTimeline() {
const [focusedIndex, setFocusedIndex] = React.useState(0);
const handleKeyDown = (e: React.KeyboardEvent, index: number) => {
switch (e.key) {
case 'ArrowDown':
case 'ArrowRight':
setFocusedIndex(Math.min(index + 1, 3));
e.preventDefault();
break;
case 'ArrowUp':
case 'ArrowLeft':
setFocusedIndex(Math.max(index - 1, 0));
e.preventDefault();
break;
case 'Enter':
handleItemSelect(index);
break;
}
};
const handleItemSelect = (index: number) => {
// Handle item selection
};
return (
<div
role="list"
onKeyDown={(e) => handleKeyDown(e, focusedIndex)}
style={{ height: '330px' }}
>
<TimelineComponent>
<ItemsDirective>
{['Step 1', 'Step 2', 'Step 3', 'Step 4'].map((item, index) => (
<ItemDirective
key={index}
content={item}
role="listitem"
tabIndex={focusedIndex === index ? 0 : -1}
/>
))}
</ItemsDirective>
</TimelineComponent>
</div>
);
}Screen Reader Support
Screen readers rely on semantic HTML and ARIA to convey content structure and meaning.
Best Practices for Screen Readers
1. Use semantic headings:
<div>
<h2>Timeline Title</h2>
<TimelineComponent>
<ItemsDirective>
<ItemDirective content="Event 1" />
</ItemsDirective>
</TimelineComponent>
</div>2. Provide descriptive labels:
<TimelineComponent
aria-label="Project development timeline showing planning, design, development, and deployment phases"
>
<ItemsDirective>
<ItemDirective
content="Planning"
aria-describedby="phase1-desc"
/>
<div id="phase1-desc" style={{ display: 'none' }}>
Initial project planning and requirements gathering phase
</div>
</ItemsDirective>
</TimelineComponent>3. Ensure meaningful content:
// ✅ Good - Clear, descriptive content
<ItemDirective content="Project approved by stakeholders" oppositeContent="March 15, 2026" />
// ❌ Poor - Vague, unclear meaning
<ItemDirective content="Done" oppositeContent="Date 1" />4. Test with screen readers:
- NVDA (Windows, free)
- JAWS (Windows, commercial)
- VoiceOver (macOS, built-in)
- TalkBack (Android, built-in)
Color Contrast
Ensure sufficient color contrast for readability, especially for users with low vision.
WCAG AA Requirements
- Normal text: Minimum 4.5:1 contrast ratio
- Large text: Minimum 3:1 contrast ratio
Checking Contrast
// Good contrast examples
const goodContrast = {
dark: '#000000', // Black on white = 21:1 ✅
blue: '#0066cc', // Blue on white = 8.6:1 ✅
gray: '#666666', // Gray on white = 7:1 ✅
};
// Poor contrast (avoid)
const poorContrast = {
light: '#cccccc', // Light gray on white = 1.8:1 ❌
tan: '#e8dcc8', // Tan on white = 2:1 ❌
};Implementing Good Contrast
<TimelineComponent
cssClass='high-contrast-theme'
style={{ backgroundColor: '#ffffff' }}
>
<ItemsDirective>
<ItemDirective
content="Important Event"
cssClass="text-dark"
style={{ color: '#000000' }}
/>
</ItemsDirective>
</TimelineComponent>CSS for contrast:
.high-contrast-theme .e-timeline-dot {
background-color: #000000;
border-color: #000000;
}
.high-contrast-theme .text-dark {
color: #000000;
background-color: #ffffff;
}
.high-contrast-theme .e-timeline-connector {
border-color: #000000;
}Right-to-Left (RTL) Support
Timeline automatically reverses layout for right-to-left languages like Arabic, Hebrew, and Urdu.
Enabling RTL
// Set HTML direction
<html dir="rtl" lang="ar">
<TimelineComponent>
<ItemsDirective>
<ItemDirective content="الحدث الأول" />
<ItemDirective content="الحدث الثاني" />
</ItemsDirective>
</TimelineComponent>
</html>Or via CSS:
body {
direction: rtl;
text-align: right;
}RTL Considerations
- Timeline flows right-to-left automatically
- Content alignment reverses appropriately
- Alignment modes adapt (Before becomes After, etc.)
- Text directionality is preserved
// RTL automatically handled
<TimelineComponent orientation='Vertical' align='Before'>
{/* In RTL context, this renders with appropriate direction */}
</TimelineComponent>Mobile Device Accessibility
Timeline supports accessible touch interactions and responsive layouts for mobile devices.
Touch-Friendly Design
function MobileAccessibleTimeline() {
return (
<div
style={{
height: '100vh',
padding: '10px'
}}
>
<TimelineComponent
orientation='Vertical'
align='Before'
cssClass='mobile-timeline'
>
<ItemsDirective>
<ItemDirective
content="Milestone 1"
oppositeContent="March 2026"
style={{ minHeight: '60px' }} // Touch-friendly size
/>
<ItemDirective
content="Milestone 2"
oppositeContent="April 2026"
style={{ minHeight: '60px' }}
/>
</ItemsDirective>
</TimelineComponent>
</div>
);
}CSS for mobile:
@media (max-width: 768px) {
.mobile-timeline .e-timeline-item {
min-height: 60px;
}
.mobile-timeline .e-timeline-dot {
--dot-size: 18px;
}
.mobile-timeline .e-timeline-content {
font-size: 16px;
}
}Responsive Text Sizing
/* Readable font sizes on all devices */
.e-timeline-content {
font-size: clamp(14px, 2vw, 16px);
}
.e-timeline-item {
padding: clamp(8px, 2vw, 16px);
}Accessibility Best Practices Checklist
- [ ] Use semantic HTML (
<section>,<h2>,<article>) - [ ] Provide
aria-labelfor container or list - [ ] Ensure text contrast meets WCAG AA (4.5:1 minimum)
- [ ] Support keyboard navigation (Tab, Arrow keys)
- [ ] Test with screen readers (NVDA, JAWS, VoiceOver)
- [ ] Use meaningful, descriptive content
- [ ] Ensure color isn't the only differentiator
- [ ] Include alt text for images in dots
- [ ] Support RTL languages if applicable
- [ ] Test on mobile devices
- [ ] Provide visible focus indicators
- [ ] Use
disabledstate for unavailable items
Accessibility Testing
Automated Testing
Use accessibility testing tools to validate compliance:
# Install Axe-core
npm install --save-dev axe-core
# Install Accessibility Checker
npm install --save-dev accessibility-checkerManual Testing
1. Keyboard navigation: Navigate using only Tab, Shift+Tab, and Arrow keys 2. Screen reader: Test with NVDA, JAWS, or VoiceOver 3. Color contrast: Verify contrast ratios with tools like WebAIM 4. Zoom: Test at 200% zoom level 5. Responsive: Test on mobile and tablet sizes 6. Focus: Verify visible focus indicators on all interactive elements
Example Test Case
// Test component with accessibility features
function AccessibleTimelineTest() {
return (
<div
role="region"
aria-label="Project Timeline"
style={{ height: '400px' }}
>
<h2 id="timeline-title">Development Phases</h2>
<TimelineComponent
role="list"
aria-describedby="timeline-title"
>
<ItemsDirective>
<ItemDirective
role="listitem"
content="Planning"
oppositeContent="Week 1"
aria-label="Planning phase: Week 1"
/>
<ItemDirective
role="listitem"
content="Development"
oppositeContent="Weeks 2-4"
aria-label="Development phase: Weeks 2 to 4"
/>
</ItemsDirective>
</TimelineComponent>
</div>
);
}Resources
- WCAG 2.2 Guidelines
- Section 508 Compliance
- WAI-ARIA Authoring Practices
- WebAIM Contrast Checker
- NVDA Screen Reader
Advanced Features
Table of Contents
- Template Customization
- Template Context
- Reverse Property
- Complex Template Examples
- When to Use Templates
Template Customization
The Timeline component's template property enables complete custom rendering of timeline items, replacing the default structure entirely. This provides maximum flexibility for complex layouts.
Basic Template Structure
Templates receive context with item data and can return any JSX:
const templateFunction = (props: any) => (
<div className={`template-container item-${props.itemIndex}`}>
<div className="content-container">
<div className="timeline-content">{props.item.content}</div>
</div>
<div className="content-connector"></div>
<div className="progress-line">
<span className="indicator"></span>
</div>
</div>
);
<TimelineComponent template={templateFunction}>
<ItemsDirective>
<ItemDirective content="Event 1" />
<ItemDirective content="Event 2" />
</ItemsDirective>
</TimelineComponent>Global vs Item-Level Templates
Global template (via TimelineComponent template):
- Applied to all items automatically
- Controls entire item rendering
- Best for consistent layouts
Item-level template (via ItemDirective content):
- Applied to individual item content only
- Doesn't replace dot or structure
- Best for content-specific customization
// Global template - replaces entire item structure
<TimelineComponent template={globalTemplate}>
// Item-level template - replaces content only
<ItemDirective content={itemContentTemplate} />Template Context
The template function receives context with the following properties:
Available Context Properties
interface TemplateContext {
item: TimelineItemModel; // Current item data
itemIndex: number; // Zero-based index of the item
}Item Model Properties
interface TimelineItemModel {
content?: string | Function; // Main content
oppositeContent?: string | Function; // Secondary content
dotCss?: string; // CSS class for dot
cssClass?: string; // CSS class for item
disabled?: boolean; // Disabled state
}Accessing Context in Template
Templates receive props object with structure:
interface TemplateProps {
item: TimelineItemModel; // Current item object
itemIndex: number; // Index (0-based)
}Example accessing context:
const template = (props: any) => {
// props.itemIndex - number (0, 1, 2, 3...)
// props.item - the TimelineItemModel object
// props.item.content - main content
// props.item.oppositeContent - opposite side content
// props.item.dotCss - dot styling classes
// props.item.cssClass - item styling classes
// props.item.disabled - disabled state
return (
<div>
<h4>Item #{props.itemIndex}</h4>
<p>{props.item.content}</p>
<small>{props.item.oppositeContent}</small>
</div>
);
};
// Usage in both pattern approaches:
// Pattern 1 - Global template
<TimelineComponent template={template}>
<ItemsDirective>...</ItemsDirective>
</TimelineComponent>
// Pattern 2 - Global template with items array
<TimelineComponent template={template} items={items} />Context Properties in Detail:
| Property | Type | Description |
|---|---|---|
props.itemIndex | number | Zero-based index of current item (0, 1, 2...) |
props.item.content | string/JSX | Main event text/template |
props.item.oppositeContent | string/JSX | Secondary content (opposite side) |
props.item.dotCss | string | CSS classes for dot (icons, colors) |
props.item.cssClass | string | CSS classes for item styling |
props.item.disabled | boolean | Whether item is disabled |
Reverse Property
The reverse property inverts the display order of timeline items, making the last item appear first. This is useful for activity feeds, audit logs, and reverse chronological displays.
Basic Reverse Example
<TimelineComponent reverse={true}>
<ItemsDirective>
<ItemDirective content='Latest action' />
<ItemDirective content='Previous action' />
<ItemDirective content='Earlier action' />
</ItemsDirective>
</TimelineComponent>Result: Items display in reverse order (newest first).
Reverse with Alignment
<TimelineComponent
reverse={true}
align='Alternate'
orientation='Vertical'
>
<ItemsDirective>
<ItemDirective content='User logged out' oppositeContent='2:30 PM' />
<ItemDirective content='User updated profile' oppositeContent='2:15 PM' />
<ItemDirective content='User logged in' oppositeContent='1:00 PM' />
</ItemsDirective>
</TimelineComponent>Use Cases for Reverse
// Activity Feed (newest first)
function ActivityFeed() {
return (
<TimelineComponent reverse={true} align='Before'>
<ItemsDirective>
<ItemDirective
content='John commented'
oppositeContent='Just now'
/>
<ItemDirective
content='Jane submitted PR'
oppositeContent='5 min ago'
/>
<ItemDirective
content='Build passed'
oppositeContent='10 min ago'
/>
</ItemsDirective>
</TimelineComponent>
);
}
// Audit Log (most recent first)
function AuditLog() {
return (
<TimelineComponent reverse={true} align='Before'>
<ItemsDirective>
<ItemDirective
content='Admin deleted user'
oppositeContent='2:45 PM'
/>
<ItemDirective
content='Admin updated permissions'
oppositeContent='2:30 PM'
/>
<ItemDirective
content='New user created'
oppositeContent='2:00 PM'
/>
</ItemsDirective>
</TimelineComponent>
);
}Complex Template Examples
Example 1: Card-Style Timeline
interface TimelineEvent {
title: string;
description: string;
date: string;
status: 'success' | 'pending' | 'warning';
author?: string;
}
const events: TimelineEvent[] = [
{
title: 'Project Approved',
description: 'Client approved final design and approved budget',
date: 'Mar 15, 2026',
status: 'success',
author: 'Project Manager'
},
{
title: 'Design Review',
description: 'Stakeholders reviewed and approved design mockups',
date: 'Mar 10, 2026',
status: 'success',
author: 'Design Lead'
},
{
title: 'Requirements Gathering',
description: 'Collected business requirements from stakeholders',
date: 'Mar 1, 2026',
status: 'success',
author: 'Business Analyst'
}
];
function CardTimeline() {
const cardTemplate = (props: any) => {
const event = events[props.itemIndex];
return (
<div className="card-wrapper">
<div className={`card card-${event.status}`}>
<div className="card-header">
<span className={`status-badge badge-${event.status}`}>
{event.status}
</span>
<span className="card-date">{event.date}</span>
</div>
<div className="card-body">
<h5 className="card-title">{event.title}</h5>
<p className="card-description">{event.description}</p>
{event.author && (
<small className="card-author">by {event.author}</small>
)}
</div>
</div>
</div>
);
};
return (
<div style={{ height: '600px', padding: '20px' }}>
<TimelineComponent
template={cardTemplate}
cssClass='card-timeline'
>
<ItemsDirective>
{events.map((event, index) => (
<ItemDirective key={index} content={event.title} />
))}
</ItemsDirective>
</TimelineComponent>
</div>
);
}CSS for Card Timeline:
.card-timeline {
--dot-size: 16px;
padding: 20px;
}
.card-wrapper {
margin: 20px 0;
}
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: white;
}
.card-success {
border-left: 4px solid #28a745;
}
.card-pending {
border-left: 4px solid #ffc107;
}
.card-warning {
border-left: 4px solid #dc3545;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.status-badge {
font-size: 12px;
padding: 4px 8px;
border-radius: 4px;
font-weight: bold;
}
.badge-success {
background-color: #d4edda;
color: #155724;
}
.badge-pending {
background-color: #fff3cd;
color: #856404;
}
.badge-warning {
background-color: #f8d7da;
color: #721c24;
}
.card-title {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: 600;
}
.card-description {
margin: 0 0 8px 0;
color: #666;
font-size: 14px;
}
.card-author {
color: #999;
display: block;
}Example 2: Progress Timeline with Percentage
interface ProjectPhase {
name: string;
progress: number;
startDate: string;
endDate: string;
}
const phases: ProjectPhase[] = [
{ name: 'Planning', progress: 100, startDate: 'Jan 1', endDate: 'Jan 15' },
{ name: 'Design', progress: 100, startDate: 'Jan 16', endDate: 'Feb 15' },
{ name: 'Development', progress: 65, startDate: 'Feb 16', endDate: 'Apr 15' },
{ name: 'Testing', progress: 0, startDate: 'Apr 16', endDate: 'May 15' }
];
function ProgressTimeline() {
const progressTemplate = (props: any) => {
const phase = phases[props.itemIndex];
return (
<div className="progress-item">
<div className="progress-header">
<h4>{phase.name}</h4>
<span className="progress-percent">{phase.progress}%</span>
</div>
<div className="progress-bar-container">
<div
className="progress-bar"
style={{ width: `${phase.progress}%` }}
/>
</div>
<div className="progress-dates">
<span>{phase.startDate} - {phase.endDate}</span>
</div>
</div>
);
};
return (
<div style={{ height: '500px', padding: '20px' }}>
<TimelineComponent
template={progressTemplate}
orientation='Vertical'
align='Before'
>
<ItemsDirective>
{phases.map((phase, index) => (
<ItemDirective key={index} content={phase.name} />
))}
</ItemsDirective>
</TimelineComponent>
</div>
);
}CSS for Progress Timeline:
.progress-item {
padding: 12px;
background-color: #f9f9f9;
border-radius: 6px;
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.progress-header h4 {
margin: 0;
font-size: 14px;
}
.progress-percent {
font-weight: bold;
color: #0066cc;
}
.progress-bar-container {
height: 8px;
background-color: #e0e0e0;
border-radius: 4px;
overflow: hidden;
margin-bottom: 8px;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #0066cc, #00d4ff);
border-radius: 4px;
transition: width 0.3s ease;
}
.progress-dates {
font-size: 12px;
color: #999;
}When to Use Templates
Use Global Template When:
- ✅ Completely custom item structure needed
- ✅ Complex layouts beyond content + oppositeContent
- ✅ Interactive elements within items
- ✅ Consistent layout for all items
- ✅ Performance optimization needed (virtual rendering)
Example:
// Full custom rendering needed
const customTemplate = (props: any) => (
<div className="complex-item">
<aside className="sidebar">
<img src={props.item.imageUrl} />
</aside>
<main className="content">
<h3>{props.item.title}</h3>
<p>{props.item.description}</p>
<button>Details</button>
</main>
</div>
);
<TimelineComponent template={customTemplate} />Use Item Content Template When:
- ✅ Only content needs customization
- ✅ Default dot and connector are fine
- ✅ Rich content formatting needed
- ✅ Templates vary per item
- ✅ Simpler implementation
Example:
// Only content is different per item
<ItemDirective
content={(props: any) => (
<div>
<h4>Event Title</h4>
<p>Description here</p>
</div>
)}
/>Use Standard Properties When:
- ✅ Simple text content sufficient
- ✅ Default styling meets requirements
- ✅ Performance is critical
- ✅ Minimal customization needed
Example:
// Keep it simple
<ItemDirective
content="Simple event"
oppositeContent="Date"
/>Performance Considerations
Template Performance Tips: 1. Avoid heavy computations in template functions 2. Memoize template functions if complex 3. Use CSS for styling over inline styles 4. Consider virtual scrolling for 100+ items 5. Profile with browser DevTools
Example with Memoization:
const memoizedTemplate = React.useMemo(() => {
return (props: any) => {
// Complex template logic here
return <div>Content</div>;
};
}, [dependencies]);
<TimelineComponent template={memoizedTemplate} />Events and Callbacks
Table of Contents
- Created Event
- BeforeItemRender Event
- Event Handling Patterns
- Practical Event Use Cases
- Tips and Troubleshooting
Created Event
The created event fires when the TimelineComponent finishes rendering and is ready for interaction. Use this event to perform initialization tasks after the component is fully loaded.
Basic Created Event
import { TimelineComponent, ItemsDirective, ItemDirective } from '@syncfusion/ej2-react-layouts';
function App() {
const handleCreated = () => {
console.log('Timeline component created and ready');
// Perform post-initialization tasks
};
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent created={handleCreated}>
<ItemsDirective>
<ItemDirective content='Planning' />
<ItemDirective content='Developing' />
<ItemDirective content='Testing' />
<ItemDirective content='Launch' />
</ItemsDirective>
</TimelineComponent>
</div>
);
}
export default App;Common Created Event Use Cases
Initialize external libraries after timeline loads:
const handleCreated = () => {
// Initialize tooltips
const tooltips = new Tooltip('#timeline [title]');
// Setup event listeners
document.querySelectorAll('.e-timeline-item').forEach(item => {
item.addEventListener('mouseenter', () => {
// Custom hover behavior
});
});
};Trigger animations or visual effects:
const handleCreated = () => {
// Add animation class to items
const items = document.querySelectorAll('.e-timeline-item');
items.forEach((item, index) => {
setTimeout(() => {
item.classList.add('fade-in');
}, index * 100);
});
};Load data from API:
const [loading, setLoading] = React.useState(true);
const handleCreated = async () => {
try {
const response = await fetch('/api/timeline-events');
const data = await response.json();
// Update state with fetched data
setLoading(false);
} catch (error) {
console.error('Failed to load timeline data:', error);
}
};BeforeItemRender Event
The beforeItemRender event fires before rendering each timeline item. Use this event to dynamically customize individual items based on data or conditions.
Basic BeforeItemRender Event
import { TimelineComponent, ItemsDirective, ItemDirective, TimelineRenderingEventArgs } from '@syncfusion/ej2-react-layouts';
function App() {
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
console.log('Rendering item:', args.item.content);
// Customize item before rendering
};
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent beforeItemRender={handleBeforeItemRender}>
<ItemsDirective>
<ItemDirective content='Planning' />
<ItemDirective content='Developing' />
<ItemDirective content='Testing' />
<ItemDirective content='Launch' />
</ItemsDirective>
</TimelineComponent>
</div>
);
}
export default App;TimelineRenderingEventArgs Properties
The event argument provides:
item- The current TimelineItem being rendereditemIndex- The index of the current item (0-based)element- The DOM element for the item (if available)
Dynamic Content Customization
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
// Customize based on item index
if (args.itemIndex === 0) {
args.item.cssClass = 'first-item';
}
if (args.itemIndex === args.itemIndex - 1) {
args.item.cssClass = 'last-item';
}
};Conditional Styling Based on Data
interface TimelineEvent {
content: string;
status: 'completed' | 'in-progress' | 'pending';
importance: 'high' | 'normal' | 'low';
}
const events: TimelineEvent[] = [
{ content: 'Kickoff', status: 'completed', importance: 'high' },
{ content: 'Design Review', status: 'completed', importance: 'high' },
{ content: 'Development', status: 'in-progress', importance: 'high' },
{ content: 'Testing', status: 'pending', importance: 'normal' }
];
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
const event = events[args.itemIndex];
// Apply status-based styling
args.item.cssClass = `status-${event.status}`;
// Highlight important items
if (event.importance === 'high') {
args.item.dotCss = (args.item.dotCss || '') + ' dot-highlight';
}
};
function App() {
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent beforeItemRender={handleBeforeItemRender}>
<ItemsDirective>
{events.map((event, index) => (
<ItemDirective key={index} content={event.content} />
))}
</ItemsDirective>
</TimelineComponent>
</div>
);
}CSS for Status Styling
.status-completed {
--dot-color: #28a745;
}
.status-in-progress {
--dot-color: #ffc107;
}
.status-pending {
--dot-color: #ccc;
}
.dot-highlight {
--dot-size: 24px;
box-shadow: 0 0 12px rgba(255, 107, 107, 0.5);
}Event Handling Patterns
Multiple Events
function TimelineWithEvents() {
const handleCreated = () => {
console.log('Timeline ready');
};
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
// Add alternating row styling
if (args.itemIndex % 2 === 0) {
args.item.cssClass = (args.item.cssClass || '') + ' even-item';
}
};
return (
<div style={{ height: '400px' }}>
<TimelineComponent
created={handleCreated}
beforeItemRender={handleBeforeItemRender}
>
<ItemsDirective>
<ItemDirective content='Event 1' />
<ItemDirective content='Event 2' />
<ItemDirective content='Event 3' />
<ItemDirective content='Event 4' />
</ItemsDirective>
</TimelineComponent>
</div>
);
}Event with State Management
function TimelineWithState() {
const [initialized, setInitialized] = React.useState(false);
const [itemCount, setItemCount] = React.useState(0);
const handleCreated = () => {
setInitialized(true);
console.log('Timeline initialized');
};
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
setItemCount(args.itemIndex + 1);
// Add animation class
args.item.cssClass = (args.item.cssClass || '') + ' animate-item';
};
return (
<div>
<div>Status: {initialized ? 'Ready' : 'Loading'}</div>
<div>Items rendered: {itemCount}</div>
<div style={{ height: '350px' }}>
<TimelineComponent
created={handleCreated}
beforeItemRender={handleBeforeItemRender}
>
<ItemsDirective>
<ItemDirective content='Step 1' />
<ItemDirective content='Step 2' />
<ItemDirective content='Step 3' />
</ItemsDirective>
</TimelineComponent>
</div>
</div>
);
}Practical Event Use Cases
Use Case 1: Log Analytics
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
// Track which timeline items are rendered
analytics.track('timeline_item_render', {
itemIndex: args.itemIndex,
content: args.item.content
});
};
const handleCreated = () => {
// Track when timeline component loads
analytics.track('timeline_component_created', {
timestamp: new Date().toISOString()
});
};Use Case 2: Lazy Load Images
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
// Mark images for lazy loading
if (args.itemIndex > 5) {
args.item.cssClass = (args.item.cssClass || '') + ' lazy-load';
}
};Use Case 3: Highlight Current Item
const [currentIndex, setCurrentIndex] = React.useState(0);
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
if (args.itemIndex === currentIndex) {
args.item.cssClass = (args.item.cssClass || '') + ' highlighted';
}
};Use Case 4: Theme-Based Customization
const [theme, setTheme] = React.useState('light');
const handleBeforeItemRender = (args: TimelineRenderingEventArgs) => {
args.item.cssClass = (args.item.cssClass || '') + ` theme-${theme}`;
};Tips and Troubleshooting
Event not firing?
- Ensure callback function is properly defined
- Check for TypeScript type errors (use
TimelineRenderingEventArgstype) - Verify component is rendering (check console for errors)
How to cancel default behavior?
- Set
args.cancel = trueif the event supports it - Check Syncfusion documentation for cancellable events
Performance with many items?
- Use
beforeItemRenderfor selective item customization - Avoid heavy operations in event handlers
- Consider virtual scrolling for 100+ items
Accessing rendered DOM?
- Use
args.elementto get the rendered DOM element (if available) - Reference:
document.querySelectorAll('.e-timeline-item')aftercreatedevent
Getting Started with React Timeline
Table of Contents
- Installation and Setup
- CSS Import Setup
- Creating a React Application
- Basic Timeline Component
- Adding Content to Timeline Items
- Container Height
- Running the Application
- Verifying Installation
Installation and Setup
Dependencies
The Timeline component requires the following npm packages:
@syncfusion/ej2-react-layouts
@syncfusion/ej2-base
@syncfusion/ej2-layouts
@syncfusion/ej2-react-baseInstalling the Package
Install the Timeline component using npm:
npm install @syncfusion/ej2-react-layouts --saveThis command automatically installs all required dependencies.
CSS Import Setup
Add CSS references to your application. Import the required CSS files in your App.tsx or App.jsx:
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-layouts/styles/tailwind3.css";Available Themes:
tailwind3.css(default, modern design)bootstrap5.3.css(Bootstrap styling)fluent2.css(Microsoft Fluent design)material3.css(Material design)
Choose based on your application's design system.
Creating a React Application
Using Vite (Recommended)
npm create vite@latest my-timeline-app -- --template react
cd my-timeline-app
npm run devFor TypeScript:
npm create vite@latest my-timeline-app -- --template react-ts
cd my-timeline-app
npm run devUsing Create React App
npx create-react-app my-timeline-app
cd my-timeline-app
npm startBasic Timeline Component
Importing Components
import { TimelineComponent, ItemsDirective, ItemDirective } from '@syncfusion/ej2-react-layouts';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import './App.css';Pattern 1: ItemsDirective and ItemDirective (JSX-Based)
import { TimelineComponent, ItemsDirective, ItemDirective } from '@syncfusion/ej2-react-layouts';
import '@syncfusion/ej2-base/styles/tailwind3.css';
import '@syncfusion/ej2-layouts/styles/tailwind3.css';
function App() {
return (
<div id='timeline' style={{ height: '350px' }}>
<TimelineComponent>
<ItemsDirective>
<ItemDirective />
<ItemDirective />
<ItemDirective />
<ItemDirective />
</ItemsDirective>
</TimelineComponent>
</div>
);
}
export default App;Pattern 2: Items Array Property (Data-Driven)
import { TimelineComponent, TimelineItemModel } from '@syncfusion/ej2-react-layouts';
import '@syncfusion/ej2-base/styles/tailwind3.css';
import '@syncfusion/ej2-layouts/styles/tailwind3.css';
function App() {
const timelineItems: TimelineItemModel[] = [
{ content: 'Cart' },
{ content: 'Personal Info' },
{ content: 'Delivery Address' },
{ content: 'Payment' }
];
return (
<div id='timeline' style={{ height: '350px' }}>
<TimelineComponent items={timelineItems} />
</div>
);
}
export default App;Pattern Selection Guide:
- ItemsDirective: Use for static JSX-based timelines with individual control per item
- items property: Use for dynamic data from APIs, databases, or when items are managed in state
Adding Content to Timeline Items
String Content
Add text content to each timeline item:
function App() {
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Shipped' />
<ItemDirective content='Departed' />
<ItemDirective content='Arrived' />
<ItemDirective content='Out for Delivery' />
</ItemsDirective>
</TimelineComponent>
</div>
);
}Adding Opposite Content
Display secondary content on the opposite side:
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Breakfast' oppositeContent='8:00 AM' />
<ItemDirective content='Lunch' oppositeContent='1:00 PM' />
<ItemDirective content='Dinner' oppositeContent='8:00 PM' />
</ItemsDirective>
</TimelineComponent>Container Height
Critical: The TimelineComponent requires an explicit height. Set it via inline style:
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent>
{/* Items */}
</TimelineComponent>
</div>Without height, the timeline will not render items vertically.
Running the Application
After setting up your project and creating the App component:
npm run devOpen your browser to the provided localhost URL (typically url for Vite or url for Create React App).
Verifying Installation
Check that the timeline renders with:
- Vertical layout (default)
- 4 items displayed
- Each item has a dot indicator
- Items are connected by a vertical line
If items don't display, verify:
- CSS imports are in place
- Container has explicit height
- ItemsDirective wraps ItemDirective elements
Items and Content
Table of Contents
- Using Items Property
- String Content
- Template-Based Content
- Opposite Content
- Dot Customization
- Disabling Items
- Per-Item CSS Classes
Using Items Property
The items property accepts an array of TimelineItemModel objects for data-driven timelines.
Basic Items Array
import { TimelineComponent, TimelineItemModel } from '@syncfusion/ej2-react-layouts';
function App() {
const items: TimelineItemModel[] = [
{ content: 'Shipped' },
{ content: 'Departed' },
{ content: 'Arrived' },
{ content: 'Out for Delivery' }
];
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent items={items} />
</div>
);
}
export default App;Items with Opposite Content
const items: TimelineItemModel[] = [
{ content: 'Breakfast', oppositeContent: '8:00 AM' },
{ content: 'Lunch', oppositeContent: '1:00 PM' },
{ content: 'Dinner', oppositeContent: '8:00 PM' }
];
<TimelineComponent items={items} />Items with Dot Customization
const items: TimelineItemModel[] = [
{ content: 'Completed', dotCss: 'e-icons e-check' },
{ content: 'In Progress', dotCss: 'e-icons e-clock' },
{ content: 'Pending', dotCss: 'e-icons e-calendar' }
];
<TimelineComponent items={items} />Items with Styling
const items: TimelineItemModel[] = [
{ content: 'Success', cssClass: 'status-success' },
{ content: 'Error', cssClass: 'status-error', disabled: true },
{ content: 'Warning', cssClass: 'status-warning' }
];
<TimelineComponent items={items} />Dynamic Items from API
import { TimelineComponent, TimelineItemModel } from '@syncfusion/ej2-react-layouts';
import { useEffect, useState } from 'react';
function App() {
const [items, setItems] = useState<TimelineItemModel[]>([]);
useEffect(() => {
// Fetch from API
fetch('/api/timeline-events')
.then(res => res.json())
.then(data => setItems(data));
}, []);
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent items={items} />
</div>
);
}When to use items property:
- Data from API or database
- Dynamic item count
- State-driven updates
- Simple data structures
String Content
The simplest way to add content to timeline items is using string values via the content property.
Basic String Content
import { TimelineComponent, ItemsDirective, ItemDirective } from '@syncfusion/ej2-react-layouts';
function App() {
return (
<div id='timeline' style={{ height: '330px' }}>
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Shipped' />
<ItemDirective content='Departed' />
<ItemDirective content='Arrived' />
<ItemDirective content='Out for Delivery' />
</ItemsDirective>
</TimelineComponent>
</div>
);
}
export default App;Result: Each item displays as plain text centered on its content area.
Multiline String Content
Use newline characters for multiple lines:
<ItemDirective content='Step 1 Initialize' />Or in JavaScript template literals:
const description = `Shipped
From Warehouse A
Ready for transport`;
<ItemDirective content={description} />When to use string content:
- Simple text labels
- Status indicators (Pending, In Progress, Completed)
- Event names
- Single-line descriptions
Template-Based Content
For rich formatting, custom layouts, and dynamic data, use template functions with the content property.
Template Function Basics
The template function receives props and returns JSX:
const contentTemplate = (props: any) => (
<div className="content-container">
<div className="title">{props.item.content}</div>
<span className="description">Additional info</span>
</div>
);
<ItemDirective content={contentTemplate} />Complete Template Example
import { TimelineComponent, ItemsDirective, ItemDirective, TimelineItemModel } from '@syncfusion/ej2-react-layouts';
function App() {
const events: TimelineItemModel[] = [
{
content: 'Shipped',
description: 'Package details received',
info: 'Awaiting dispatch'
},
{
content: 'Departed',
description: 'In-transit',
info: 'International warehouse'
},
{
content: 'Arrived',
description: 'Package at nearest hub',
info: 'New York - US'
}
];
const contentTemplate = (data: any) => (
<div className="content-container">
<div className="title">{data.title || data.content}</div>
<span className="description">{data.description}</span>
<div className="info">{data.info}</div>
</div>
);
return (
<div className="container" style={{ height: '330px' }}>
<TimelineComponent id="timeline">
<ItemsDirective>
{events.map((item, index) => (
<ItemDirective
key={index}
content={() => contentTemplate(item)}
/>
))}
<ItemDirective content="Out for Delivery" />
</ItemsDirective>
</TimelineComponent>
</div>
);
}
export default App;Template with Styling
const contentTemplate = (props: any) => (
<div style={{ padding: '10px', backgroundColor: '#f5f5f5', borderRadius: '4px' }}>
<h4 style={{ margin: '0 0 5px 0' }}>{props.item.content}</h4>
<p style={{ margin: '0', fontSize: '12px', color: '#666' }}>
Additional details about the event
</p>
</div>
);When to use templates:
- Rich formatted content (multiple elements, styling)
- Dynamic content from data sources
- Complex layouts (images, badges, icons)
- Responsive content based on screen size
- Interactive elements within items
Opposite Content
Use oppositeContent to display supplementary information on the opposite side of the timeline (configurable via align property).
Basic Opposite Content
<TimelineComponent align='Before'>
<ItemsDirective>
<ItemDirective content='Breakfast' oppositeContent='8:00 AM' />
<ItemDirective content='Lunch' oppositeContent='1:00 PM' />
<ItemDirective content='Dinner' oppositeContent='8:00 PM' />
</ItemsDirective>
</TimelineComponent>Result: Main content on left, times on right (Vertical + Before).
Opposite Content as Template
Templates work for oppositeContent too:
const dateTemplate = (props: any) => (
<div style={{ fontWeight: 'bold', color: '#0066cc' }}>
{new Date(props.item.date).toLocaleDateString()}
</div>
);
<ItemDirective
content='Project completed'
oppositeContent={dateTemplate}
/>Common Opposite Content Patterns
// Timestamps
<ItemDirective content='Status Update' oppositeContent='2:30 PM' />
// Dates
<ItemDirective content='Milestone' oppositeContent='March 15, 2026' />
// Status badges
<ItemDirective
content='Deployment'
oppositeContent='✓ Success'
/>
// User info
<ItemDirective
content='Review completed'
oppositeContent='By John Doe'
/>When to use opposite content:
- Timestamps with events
- Dates with milestones
- Metadata alongside main content
- Parallel information display
- Creating balanced two-sided layouts
Dot Customization
The dotCss property lets you apply CSS classes to customize dot appearance. Combine with CSS custom properties or classes for icons, images, text, and colors.
Icons in Dots
Apply icon font classes to display icons in dots:
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Shipped' dotCss='e-icons e-package' />
<ItemDirective content='In Transit' dotCss='e-icons e-truck' />
<ItemDirective content='Delivered' dotCss='e-icons e-check' />
</ItemsDirective>
</TimelineComponent>Common Syncfusion Icons:
e-check- Checkmarke-package- Packagee-truck- Truck/vehiclee-location- Map pine-clock- Clocke-user- User
Images as Dots
Use CSS background-image to display custom images:
CSS:
.dot-image {
background-image: url('path/to/image.jpg');
background-size: cover;
background-position: center;
}React:
<ItemDirective content='Avatar' dotCss='dot-image' />Text in Dots
Display text or numbers in dots:
CSS:
.dot-text::before {
content: '1';
color: white;
font-weight: bold;
}React:
<ItemDirective content='Step 1' dotCss='dot-text' />Color Customization
CSS:
.dot-color-primary {
--dot-color: #0066cc;
}
.dot-color-success {
--dot-color: #28a745;
}
.dot-color-warning {
--dot-color: #ffc107;
}React:
<ItemDirective content='Ordered' cssClass='state-completed' dotCss='dot-color-success' />
<ItemDirective content='Processing' cssClass='state-progress' dotCss='dot-color-warning' />Size Customization
Use CSS custom property --dot-size:
CSS:
.dot-x-small {
--dot-size: 8px;
}
.dot-small {
--dot-size: 12px;
}
.dot-medium {
--dot-size: 20px;
}
.dot-large {
--dot-size: 28px;
}React:
<TimelineComponent cssClass='dot-size'>
<ItemsDirective>
<ItemDirective content='Ordered' cssClass='x-small' />
<ItemDirective content='Shipped' cssClass='small' />
<ItemDirective content='Delivered' cssClass='medium' />
<ItemDirective content='Reviewed' cssClass='large' />
</ItemsDirective>
</TimelineComponent>When to customize dots:
- Status indicators (use different colors/icons)
- Process steps (numbered dots)
- User avatars (images)
- Visual hierarchy (size variations)
- Semantic meaning (icon = action type)
Disabling Items
Use the disabled property to disable individual items, making them appear dimmed and non-interactive:
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Completed' />
<ItemDirective content='In Progress' />
<ItemDirective content='Pending' disabled={true} />
<ItemDirective content='Not Started' disabled={true} />
</ItemsDirective>
</TimelineComponent>Default: disabled={false} (enabled)
When to disable:
- Show locked or unavailable steps
- Indicate incomplete phases
- Gray out future milestones
- Show unavailable options
- Prevent user interaction on certain items
Visual Effect: Disabled items appear with reduced opacity and no interaction states.
Per-Item CSS Classes
Apply custom styles to individual items using the cssClass property:
<TimelineComponent>
<ItemsDirective>
<ItemDirective content='Success' cssClass='state-success' />
<ItemDirective content='Error' cssClass='state-error' />
<ItemDirective content='Warning' cssClass='state-warning' />
</ItemsDirective>
</TimelineComponent>CSS for per-item styling:
.state-success {
color: #28a745;
}
.state-error {
color: #dc3545;
}
.state-warning {
color: #ffc107;
}
/* Custom connectors */
.custom-connector::after {
border-color: #0066cc;
}
/* Custom backgrounds */
.highlight {
background-color: #f0f8ff;
padding: 10px;
border-radius: 4px;
}Common patterns:
- Status colors (success, error, warning, info)
- Highlighting important items
- Custom spacing or layout
- Theme variations per item
- Responsive adjustments
Combining with dotCss:
<ItemDirective
content='Completed'
dotCss='e-icons e-check dot-color-success'
cssClass='state-completed'
/>This combines dot customization with item-level styling for cohesive visual design.
Layout Configuration
Table of Contents
- Orientation Overview
- Alignment Overview
- Vertical with Before
- Vertical with After
- Vertical Alternate
- Horizontal Layouts
- Choosing Your Layout
- Globalization & Persistence
Orientation Overview
The orientation property controls whether items flow vertically or horizontally. The default is Vertical.
Vertical Orientation
Timeline items display top-to-bottom in a vertical stack:
<TimelineComponent orientation='Vertical'>
<ItemsDirective>
<ItemDirective content='Day 1, 4:00 PM' oppositeContent='Check-in' />
<ItemDirective content='Day 1, 7:00 PM' oppositeContent='Dinner' />
<ItemDirective content='Day 2, 5:30 AM' oppositeContent='Sunrise' />
<ItemDirective content='Day 2, 8:00 AM' oppositeContent='Breakfast' />
</ItemsDirective>
</TimelineComponent>Best for:
- Long lists of events
- Mobile-first designs
- Chronological activity feeds
- Single-column layouts
Horizontal Orientation
Timeline items display left-to-right in a horizontal sequence:
<TimelineComponent orientation='Horizontal'>
<ItemsDirective>
<ItemDirective content='Day 1, 4:00 PM' oppositeContent='Check-in' />
<ItemDirective content='Day 1, 7:00 PM' oppositeContent='Dinner' />
<ItemDirective content='Day 2, 5:30 AM' oppositeContent='Sunrise' />
<ItemDirective content='Day 2, 8:00 AM' oppositeContent='Breakfast' />
</ItemsDirective>
</TimelineComponent>Best for:
- Wide desktop screens
- Process flow visualization
- Milestone progression
- Project roadmaps
- Limited number of events (3-8 items)
Alignment Overview
The align property controls how content is positioned relative to the timeline axis. There are four alignment modes.
Before Alignment
Content appears on one consistent side throughout the timeline.
Vertical + Before: Content on left, oppositeContent on right Horizontal + Before: Content on top, oppositeContent on bottom
<TimelineComponent orientation='Vertical' align='Before'>
<ItemsDirective>
<ItemDirective content='ReactJs' oppositeContent='Owned by Facebook' />
<ItemDirective content='Angular' oppositeContent='Owned by Google' />
<ItemDirective content='VueJs' oppositeContent='Owned by Evan you' />
<ItemDirective content='Svelte' oppositeContent='Owned by Rich Harris' />
</ItemsDirective>
</TimelineComponent>Use Before when:
- Comparing main events with supplementary info
- One side needs emphasis
- Consistent layout aids readability
After Alignment
Content positioning is reversed compared to Before alignment.
Vertical + After: Content on right, oppositeContent on left Horizontal + After: Content on bottom, oppositeContent on top
<TimelineComponent orientation='Vertical' align='After'>
<ItemsDirective>
<ItemDirective content='ReactJs' oppositeContent='Owned by Facebook' />
<ItemDirective content='Angular' oppositeContent='Owned by Google' />
<ItemDirective content='VueJs' oppositeContent='Owned by Evan you' />
<ItemDirective content='Svelte' oppositeContent='Owned by Rich Harris' />
</ItemsDirective>
</TimelineComponent>Use After when:
- You want reversed positioning
- Mirror layout of Before alignment
- Different visual emphasis needed
Alternate Alignment
Items alternate positions side-to-side, creating a zigzag pattern for visual variety.
<TimelineComponent orientation='Vertical' align='Alternate'>
<ItemsDirective>
<ItemDirective content='ReactJs' oppositeContent='Owned by Facebook' />
<ItemDirective content='Angular' oppositeContent='Owned by Google' />
<ItemDirective content='VueJs' oppositeContent='Owned by Evan you' />
<ItemDirective content='Svelte' oppositeContent='Owned by Rich Harris' />
</ItemsDirective>
</TimelineComponent>Use Alternate when:
- Displaying balanced comparisons
- Showing two parallel tracks
- Creating symmetrical timelines
- Highlighting alternating event types
AlternateReverse Alignment
Inverse of Alternate, starting on the opposite side and reversing the alternation pattern.
<TimelineComponent orientation='Vertical' align='Alternatereverse'>
<ItemsDirective>
<ItemDirective content='ReactJs' oppositeContent='Owned by Facebook' />
<ItemDirective content='Angular' oppositeContent='Owned by Google' />
<ItemDirective content='VueJs' oppositeContent='Owned by Evan you' />
<ItemDirective content='Svelte' oppositeContent='Owned by Rich Harris' />
</ItemsDirective>
</TimelineComponent>Use AlternateReverse when:
- You need opposite alternation pattern
- Starting position differs from Alternate
- Different visual flow desired
Horizontal Layouts
Horizontal with Alternate (Most Common)
Ideal for milestone progression and roadmaps:
<TimelineComponent orientation='Horizontal' align='Alternate'>
<ItemsDirective>
<ItemDirective content='Planning' oppositeContent='Q1' />
<ItemDirective content='Development' oppositeContent='Q2' />
<ItemDirective content='Testing' oppositeContent='Q3' />
<ItemDirective content='Launch' oppositeContent='Q4' />
</ItemsDirective>
</TimelineComponent>Benefits:
- Balanced visual layout
- Utilizes width effectively
- Professional appearance
- Good for presentations
Choosing Your Layout
| Use Case | Orientation | Align | Reason |
|---|---|---|---|
| Activity feed | Vertical | Before | Simple chronological list |
| Career timeline | Vertical | Alternate | Balanced comparison |
| Project roadmap | Horizontal | Alternate | Wide display, milestone focus |
| Process flow | Horizontal | Before | Sequential steps, one-sided |
| Before/after | Vertical | Alternate | Visual comparison |
| Shipping tracking | Vertical | Before | Simple progression |
| Company history | Vertical | Alternate | Balanced timeline |
Content Positioning Rules
Important Positioning Rules
1. oppositeContent only displays when align mode supports it:
Before: Main content left/top, opposite right/bottomAfter: Main content right/bottom, opposite left/topAlternate: Alternates sides for both content and oppositeAlternateReverse: Reverse alternation starting position
2. Container must have height: Timeline won't flow without explicit height
3. Horizontal timelines need width: Ensure parent container has sufficient width
4. Orientation + Align combine: Both properties work together for final layout
Example: Responsive Design
function ResponsiveTimeline() {
const isSmallScreen = window.innerWidth < 768;
return (
<div style={{ height: isSmallScreen ? '600px' : '400px' }}>
<TimelineComponent
orientation={isSmallScreen ? 'Vertical' : 'Horizontal'}
align={isSmallScreen ? 'Before' : 'Alternate'}
>
<ItemsDirective>
<ItemDirective content='Event 1' oppositeContent='Date 1' />
<ItemDirective content='Event 2' oppositeContent='Date 2' />
<ItemDirective content='Event 3' oppositeContent='Date 3' />
</ItemsDirective>
</TimelineComponent>
</div>
);
}This switches to Vertical/Before on mobile for better readability.
Globalization & Persistence
Locale Property
Set the component locale for multilingual support:
<TimelineComponent locale='es'>
<ItemsDirective>
<ItemDirective content='Evento 1' />
<ItemDirective content='Evento 2' />
</ItemsDirective>
</TimelineComponent>Supported locales: en-US (default), es, fr, de, ja, ar, and many more.
Enable RTL (Right-to-Left)
Enable RTL layout for languages like Arabic, Hebrew, and Urdu:
<TimelineComponent enableRtl={true}>
<ItemsDirective>
<ItemDirective content='الحدث الأول' />
<ItemDirective content='الحدث الثاني' />
</ItemsDirective>
</TimelineComponent>Combine with locale: <TimelineComponent enableRtl={true} locale='ar'>
Enable Persistence
Persist component state between page reloads:
<TimelineComponent enablePersistence={true}>
<ItemsDirective>
<ItemDirective content='Step 1' />
<ItemDirective content='Step 2' />
</ItemsDirective>
</TimelineComponent>Use case: Multi-step wizards where users return to their position later.
Styling and Customization
Table of Contents
Connector Styling
The connector is the line connecting timeline dots. Customize it globally or per-item.
Common Connector Styling
Apply the same style to all connectors:
<TimelineComponent cssClass='custom-connector'>
<ItemsDirective>
<ItemDirective content='Eat' />
<ItemDirective content='Code' />
<ItemDirective content='Repeat' />
</ItemsDirective>
</TimelineComponent>CSS:
.custom-connector .e-timeline-connector {
border-color: #0066cc;
border-width: 3px;
}
.custom-connector .e-timeline-dot {
background-color: #0066cc;
border-color: #0066cc;
}Individual Connector Styling
Apply unique styles to specific item connectors:
<TimelineComponent cssClass='gradient-timeline'>
<ItemsDirective>
<ItemDirective content='Start' cssClass='state-initial' />
<ItemDirective content='Middle' cssClass='state-intermediate' />
<ItemDirective content='End' cssClass='state-final' />
</ItemsDirective>
</TimelineComponent>CSS:
.gradient-timeline .state-initial .e-timeline-connector {
border-color: #e74c3c;
}
.gradient-timeline .state-intermediate .e-timeline-connector {
border-color: #f39c12;
}
.gradient-timeline .state-final .e-timeline-connector {
border-color: #27ae60;
}Result: Connectors change color based on status (red → yellow → green progression).
Dashed vs Solid Connectors
/* Solid connector (default) */
.solid-connector .e-timeline-connector {
border-style: solid;
border-width: 2px;
}
/* Dashed connector */
.dashed-connector .e-timeline-connector {
border-style: dashed;
border-width: 2px;
border-color: #999;
}
/* Dotted connector */
.dotted-connector .e-timeline-connector {
border-style: dotted;
border-width: 2px;
border-color: #999;
}Dot Styling
Comprehensive customization for timeline dots using CSS classes and custom properties.
Dot Color Customization
<TimelineComponent cssClass='dot-color'>
<ItemsDirective>
<ItemDirective content='Ordered' cssClass='state-completed' />
<ItemDirective content='Shipped' cssClass='state-progress' />
<ItemDirective content='Delivered' />
</ItemsDirective>
</TimelineComponent>CSS:
.dot-color .state-completed {
--dot-color: #28a745;
}
.dot-color .state-progress {
--dot-color: #ffc107;
}
.dot-color .e-timeline-item:not(.state-completed):not(.state-progress) {
--dot-color: #ccc;
}Dot Size Variations
<TimelineComponent cssClass='dot-size'>
<ItemsDirective>
<ItemDirective content='Ordered' cssClass='x-small' />
<ItemDirective content='Shipped' cssClass='small' />
<ItemDirective content='In Transit' cssClass='medium' />
<ItemDirective content='Delivered' cssClass='large' />
</ItemsDirective>
</TimelineComponent>CSS:
.dot-size .x-small {
--dot-size: 8px;
}
.dot-size .small {
--dot-size: 12px;
}
.dot-size .medium {
--dot-size: 18px;
}
.dot-size .large {
--dot-size: 28px;
}Dot Shadow and Border Effects
<TimelineComponent cssClass='dot-shadow'>
<ItemsDirective>
<ItemDirective content='Ordered' />
<ItemDirective content='Shipped' />
<ItemDirective content='Delivered' />
</ItemsDirective>
</TimelineComponent>CSS with Shadow:
.dot-shadow .e-timeline-dot {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
border: 2px solid #fff;
}
.dot-shadow .e-timeline-dot::after {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}CSS with Outline:
.dot-outline .e-timeline-dot {
--dot-outer-space: 4px;
--dot-border: 2px solid #ccc;
background-color: transparent;
}Dot Variants (Filled, Outline, Flat)
<TimelineComponent cssClass='dot-variant'>
<ItemsDirective>
<ItemDirective content='Filled' cssClass='dot-filled' />
<ItemDirective content='Flat' cssClass='dot-flat' />
<ItemDirective content='Outlined' cssClass='dot-outlined' />
</ItemsDirective>
</TimelineComponent>CSS:
/* Filled variant (default) */
.dot-variant .dot-filled .e-timeline-dot {
background-color: #0066cc;
border: none;
}
/* Flat variant */
.dot-variant .dot-flat .e-timeline-dot {
background-color: #e8f4fd;
border: 1px solid #0066cc;
}
/* Outlined variant */
.dot-variant .dot-outlined .e-timeline-dot {
background-color: transparent;
border: 2px solid #0066cc;
}CSS Custom Properties
Syncfusion Timeline supports CSS custom properties (CSS variables) for fine-grained control.
Available Custom Properties
| Property | Default | Purpose |
|---|---|---|
--dot-size | 16px | Diameter of timeline dots |
--dot-color | #0066cc | Fill color of dots |
--dot-border | 1px solid transparent | Border style for dots |
--dot-outer-space | 0 | Outer spacing/glow effect |
--connector-color | #0066cc | Color of connecting line |
Using CSS Variables
<TimelineComponent style={{ '--dot-size': '24px', '--dot-color': '#ff6b6b' } as React.CSSProperties}>
<ItemsDirective>
<ItemDirective content='Event 1' />
<ItemDirective content='Event 2' />
</ItemsDirective>
</TimelineComponent>Or in CSS:
.my-timeline {
--dot-size: 20px;
--dot-color: #0066cc;
--connector-color: #0066cc;
}Responsive Variables
/* Desktop */
.timeline-container {
--dot-size: 20px;
}
/* Tablet */
@media (max-width: 768px) {
.timeline-container {
--dot-size: 16px;
}
}
/* Mobile */
@media (max-width: 480px) {
.timeline-container {
--dot-size: 12px;
}
}Outline Class
Apply the e-outline class to the TimelineComponent for an outline-style dot appearance:
<TimelineComponent cssClass='e-outline'>
<ItemsDirective>
<ItemDirective content='Shipped' />
<ItemDirective content='Departed' />
<ItemDirective content='Arrived' />
<ItemDirective content='Out for Delivery' />
</ItemsDirective>
</TimelineComponent>Result: Dots display with transparent fill and visible borders instead of solid fills.
When to use e-outline:
- Light/minimal design aesthetic
- Reduce visual emphasis on dots
- Consistent with outline UI patterns
- Better contrast on dark backgrounds
Complete Examples
Status-Based Timeline with Colors
function StatusTimeline() {
const items = [
{ content: 'Ordered', status: 'completed' },
{ content: 'Confirmed', status: 'completed' },
{ content: 'Processing', status: 'completed' },
{ content: 'Shipped', status: 'in-progress' },
{ content: 'Delivered', status: 'pending' }
];
return (
<div style={{ height: '400px' }}>
<TimelineComponent cssClass='status-timeline'>
<ItemsDirective>
{items.map((item, index) => (
<ItemDirective
key={index}
content={item.content}
cssClass={`status-${item.status}`}
/>
))}
</ItemsDirective>
</TimelineComponent>
</div>
);
}CSS:
.status-timeline .status-completed {
--dot-color: #28a745;
}
.status-timeline .status-in-progress {
--dot-color: #ffc107;
animation: pulse 2s infinite;
}
.status-timeline .status-pending {
--dot-color: #ccc;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}Process Flow with Icons and Styling
function ProcessFlow() {
return (
<div style={{ height: '350px' }}>
<TimelineComponent
cssClass='process-flow'
orientation='Horizontal'
align='Alternate'
>
<ItemsDirective>
<ItemDirective
content='Planning'
dotCss='e-icons e-diagram-sketch'
cssClass='step-1'
/>
<ItemDirective
content='Design'
dotCss='e-icons e-palette'
cssClass='step-2'
/>
<ItemDirective
content='Development'
dotCss='e-icons e-code'
cssClass='step-3'
/>
<ItemDirective
content='Testing'
dotCss='e-icons e-check'
cssClass='step-4'
/>
</ItemsDirective>
</TimelineComponent>
</div>
);
}CSS:
.process-flow {
--dot-size: 24px;
}
.process-flow .step-1 { --dot-color: #3498db; }
.process-flow .step-2 { --dot-color: #9b59b6; }
.process-flow .step-3 { --dot-color: #e74c3c; }
.process-flow .step-4 { --dot-color: #27ae60; }
.process-flow .e-timeline-connector {
border-width: 3px;
}Best Practices
1. Color Semantics
Use colors consistently with meaning:
- Green for success/completed
- Yellow/orange for in-progress/warning
- Red for error/failed
- Gray for disabled/pending
2. Accessibility
- Ensure sufficient color contrast (WCAG AA: 4.5:1)
- Don't rely on color alone; use icons or text
- Test with colorblind-friendly palettes
3. Performance
- Use CSS classes over inline styles when possible
- Limit animations to critical items
- Avoid excessive shadow/blur effects on many items
4. Responsive Design
@media (max-width: 768px) {
.timeline-container {
--dot-size: 14px;
}
.timeline-connector {
border-width: 1px;
}
}5. Consistency
- Use same color scheme across all timelines
- Maintain dot size ratios
- Keep connector styles uniform
- Match surrounding design system
6. Customization Strategy
1. Set global styles via TimelineComponent cssClass 2. Use per-item cssClass for variations 3. Apply dotCss for dot-specific styling 4. Use CSS custom properties for theming