Customizable React Timeline Variants Using Tailwind CSS for Any Project
A timeline component is an excellent way to present:
- Your journey (e.g., personal or professional milestones).
- A roadmap for projects or products.
- Step-by-step processes for workflows or tutorials.
In this guide, you will get code of two types of timelines: the growth timeline and the vertical timeline. Both are reusable and created with React, TypeScript, and Tailwind CSS.
What You’ll Get
- Overview: Features and functionality of the timeline component.
- How It Works: Step-by-step breakdown of its implementation.
- Code Snippets: Ready-to-use examples for building the component.
Features of the Component
- Dynamic Data Handling: The component uses a
timelineData
array to show items dynamically. - Reusable Components: Each timeline entry is a modular component (
TimelineItem
) for easy customization. - Custom Styling: Built with Tailwind CSS classes for flexibility in colors, fonts, and layout.
- Interactive Elements: Visitor can view more by clicking links.
Growth Timeline Component
React Tailwind Growth Timeline Item Component
Each timeline entry is styled to alternate positions for visual appeal. The component includes:
1import { timelineData } from './data' 2import TimelineItem from './Timeline' 3 4const Timeline = () => 5 timelineData.length > 0 && ( 6 <div className="relative my-10 flex flex-col after:absolute after:left-[calc(50%_-_2px)] after:h-full after:w-1 after:content-normal after:bg-slate-400"> 7 {timelineData.map((data, idx) => ( 8 <TimelineItem data={data} key={idx} /> 9 ))} 10 </div> 11 ) 12 13export default Timeline
React Tailwind Timeline Wrapper Component
This component acts as the container for all timeline items. It dynamically maps through the data to render each entry. The center line is styled using Tailwind's utility classes.
1import { TimelineItemType } from './data' 2 3const TimelineItem = ({ data }: { data: TimelineItemType }) => { 4 let { 5 date, 6 text, 7 link, 8 category: { tag, color, bgColor }, 9 } = data 10 11 return ( 12 <div className="group relative my-[10px] flex w-1/2 justify-end pr-[22px] odd:justify-start odd:self-end odd:pl-[22px] odd:pr-0 sm:pr-[30px] sm:odd:pl-[30px]"> 13 <div className="relative flex w-[400px] max-w-[95%] flex-col items-center rounded-[5px] bg-white px-4 py-[10px] text-center shadow-[0_0_2px_rgba(0,0,0,0.3)] after:absolute after:right-[-7.5px] after:top-[calc(50%-7.5px)] after:h-4 after:w-4 after:rotate-45 after:content-normal after:bg-white after:shadow-[1px_-1px_1px_rgba(0,0,0,0.2)] group-odd:items-center group-odd:text-center group-odd:after:left-[-7.5px] group-odd:after:right-auto group-odd:after:shadow-[-1px_1px_1px_rgba(0,0,0,0.2)] sm:max-w-[70%] md:items-end md:p-4 md:text-right md:group-odd:items-start md:group-odd:text-left"> 14 <span 15 className="absolute left-[5px] top-[5px] w-[calc(100%-10px)] p-[5px] text-center text-xs font-bold uppercase tracking-[1px] group-odd:left-auto group-odd:right-1 md:w-auto" 16 // tailwind does not allow to construct classes dynamically so for colors we have to use inline style...... https://tailwindcss.com/docs/content-configuration#dynamic-class-names 17 style={{ 18 backgroundColor: bgColor, 19 color: color ? color : '#4d4d4d', 20 }} 21 > 22 {tag} 23 </span> 24 <time className="mt-6 text-xs text-[#777] md:m-0">{date}</time> 25 <p className="my-4 max-w-64 text-sm sm:text-base">{text}</p> 26 {link && ( 27 <a 28 href={link.url} 29 className="text-sm text-[rgb(160,160,160)] underline after:ml-0.5 after:hidden after:text-xs after:content-['►'] md:no-underline md:after:inline-block" 30 target="_blank" 31 rel="" 32 > 33 {link.text} 34 </a> 35 )} 36 <span className="absolute -right-8 top-[calc(50%-10px)] z-50 h-5 w-5 rounded-[50%] border-[3px] border-slate-400 bg-white group-odd:-left-8 group-odd:right-auto sm:-right-10 sm:group-odd:-left-10" /> 37 </div> 38 </div> 39 ) 40} 41 42export default TimelineItem
Timeline Data
The timeline is populated with structured data, making it reusable and easy to update. The TimelineItemType
interface ensures type safety, while individual events can include optional links.
1// const bgColors = ['#DFF4D9', '#EBE8F2', '#FDE0C3', '#DFF3F7', '#F8F2DE', '#FEE1D3'] 2 3export interface TimelineItemType { 4 text: string 5 date: string 6 category: { 7 tag: string 8 color?: string 9 bgColor: string 10 } 11 link?: { 12 url: string 13 text: string 14 } 15} 16 17const timelineData = [ 18 { 19 text: 'Published my article site build with Gatsbyjs', 20 date: 'May 26, 2024', 21 category: { 22 tag: 'project', 23 bgColor: '#FEE1D3', 24 }, 25 link: { 26 url: '#', 27 text: 'Check it out', 28 }, 29 }, 30 { 31 text: 'Finished first MVP of passion project Project Name', 32 date: 'February 04, 2024', 33 category: { 34 tag: 'project', 35 bgColor: '#EBE8F2', 36 }, 37 link: { 38 url: '#', 39 text: 'Check it out', 40 }, 41 }, 42 { 43 text: 'Acquired a desk in workspace to start my own setup', 44 date: 'November 04, 2023', 45 category: { 46 tag: 'Office', 47 bgColor: '#DFF4D9', 48 }, 49 }, 50 { 51 text: 'Awarded Top 7 badge for having at least one post featured in the weekly "must-reads" from Dev.to', 52 date: 'March 17, 2021', 53 category: { 54 tag: 'award', 55 bgColor: '#FFFAD1', 56 }, 57 link: { 58 url: 'https://dev.to/abdulbasit313', 59 text: 'Profile link', 60 }, 61 }, 62 { 63 text: 'Started working as MERN Stack Developer at Acme Lab', 64 date: 'October 08, 2020', 65 category: { 66 tag: 'job', 67 bgColor: '#FEE1D3', 68 }, 69 link: { 70 url: '#', 71 text: 'Check it out', 72 }, 73 }, 74 { 75 text: 'completed the freeCodeCamp.org Responsive Web Design', 76 date: 'August 1, 2018', 77 category: { 78 tag: 'certification', 79 bgColor: '#DFF4D9', 80 }, 81 link: { 82 url: 'https://www.freecodecamp.org/certification/basit_miyanji/responsive-web-design', 83 text: 'Check it out here', 84 }, 85 }, 86] 87 88export { timelineData }
How Timeline Data Works
Data Structure:
Timeline data is defined in a structured array with:
- Text: Description of the milestone or step.
- Date: Timestamp for each event.
- Category: Custom tags with colors and backgrounds.
- Links (Optional): Add URLs for external references.
React Tailwind Vertical Timeline
Preview
Tailwind Vertical Timeline Component Code with React
Just like above growth timeline component code, this component is also divided into three parts:
- Main Timeline Component
- Timeline Item
- Timeline Data
1const timelineData = [ 2 { 3 title: 'Launched Personal Portfolio Website', 4 description: 5 'Built a portfolio website to showcase projects and achievements using React and Tailwind CSS.', 6 date: 'Jan, 2023', 7 }, 8 { 9 title: 'Started a Full-Stack Developer Role', 10 description: 11 'Joined Tech Solutions as a developer. Built web applications and APIs with Node.js and React.', 12 date: 'Jun, 2023', 13 }, 14 { 15 title: 'Conducted a JavaScript Workshop', 16 description: 17 'Hosted a workshop on JavaScript basics, ES6 features, and coding challenges for 100 participants.', 18 date: 'Sep, 2023', 19 }, 20 { 21 title: 'Released an Open-Source Library', 22 description: 23 'Published a React component library for accessible, responsive UI. Gained 500 stars in a month.', 24 date: 'Feb, 2024', 25 }, 26 { 27 title: 'Completed Advanced React Course', 28 description: 29 'Finished a React and TypeScript course covering state, server-side rendering, and testing.', 30 date: 'Jun, 2024', 31 }, 32 { 33 title: 'Built a Quiz App for Education', 34 description: 35 'Created a quiz app with a dashboard and student interface using React and Firebase.', 36 date: 'Dec, 2024', 37 }, 38] 39 40interface PropsType { 41 title: string 42 description: string 43 date: string 44} 45 46const TimelineItem: React.FC<PropsType> = ({ title, description, date }) => { 47 return ( 48 <div className="group relative py-6 pl-8 sm:pl-32"> 49 <div className="mb-1 flex flex-col items-start before:absolute before:left-2 before:h-full before:-translate-x-1/2 before:translate-y-3 before:self-start before:bg-slate-300 before:px-px after:absolute after:left-2 after:box-content after:h-2 after:w-2 after:-translate-x-1/2 after:translate-y-1.5 after:rounded-full after:border-4 after:border-slate-50 after:bg-indigo-600 group-last:before:hidden sm:flex-row sm:before:left-0 sm:before:ml-[6.5rem] sm:after:left-0 sm:after:ml-[6.5rem]"> 50 <time className="left-0 mb-3 inline-flex h-6 w-20 translate-y-0.5 items-center justify-center rounded-full bg-emerald-100 text-xs font-semibold uppercase text-emerald-600 sm:absolute sm:mb-0"> 51 {date} 52 </time> 53 <div className="text-xl font-bold text-slate-900">{title}</div> 54 </div> 55 <div className="text-slate-500">{description}</div> 56 </div> 57 ) 58} 59 60const Timeline = () => { 61 return ( 62 <div> 63 {timelineData.length > 0 && 64 timelineData.map((item, idx) => ( 65 <TimelineItem 66 key={idx} 67 title={item.title} 68 description={item.description} 69 date={item.date} 70 /> 71 ))} 72 </div> 73 ) 74} 75 76export default Timeline
Conclusion
- Prepare Your Data: Write the timeline data with meaningful events.
- Integrate Components: Use the
Timeline
andTimelineItem
components in your project. - Style with Tailwind: Customize the appearance using Tailwind's utility classes.
- Deploy: Add the timeline component to showcase your journey, roadmap, or milestones.
If you have a component or template request, feel free to reach out to me!