Eldora UI
Eldora UI
  1. Components
  2. Sections
  3. Timeline

Timeline

A drop zone is an area into which one or multiple objects can be dragged and dropped.

Acme was founded in Milan, Italy
Pretium lectus quam id leo. Urna et pharetra pharetra massa massa. Adipiscing enim eu neque aliquam vestibulum morbi blandit cursus risus.
Reached 5K customers
Pretium lectus quam id leo. Urna et pharetra pharetra massa massa. Adipiscing enim eu neque aliquam vestibulum morbi blandit cursus risus.
Acquired various companies, inluding Technology Inc.
Pretium lectus quam id leo. Urna et pharetra pharetra massa massa. Adipiscing enim eu neque aliquam vestibulum morbi blandit cursus risus.
Acme went public at the New York Stock Exchange
Pretium lectus quam id leo. Urna et pharetra pharetra massa massa. Adipiscing enim eu neque aliquam vestibulum morbi blandit cursus risus.
<VerticalTimeline01/>

Installation

Copy and paste the following code into your project for default variant.

import { Caveat } from 'next/font/google'

const caveat = Caveat({
  subsets: ['latin'],
  variable: '--font-caveat',
  display: 'swap'
})

interface TimelineItemProps {
  date: string
  label: string
  title: string
  content: string
}

export default function VerticalTimeline01({ items }: { items: TimelineItemProps[] }) {
  return (
    <div className={`${caveat.variable} -my-6`}>

      {items.map((item, index) => (
        <div key={index} className="relative pl-8 sm:pl-32 py-6 group">
          {/* Purple label */}
         
          {/* Time + Title */}
          <div className="flex flex-col sm:flex-row items-start mb-1 group-last:before:hidden before:absolute before:left-2 sm:before:left-0 before:h-full before:px-px before:bg-slate-300 sm:before:ml-[6.5rem] before:self-start before:-translate-x-1/2 before:translate-y-3 after:absolute after:left-2 sm:after:left-0 after:w-2 after:h-2 after:bg-indigo-600 after:border-4 after:box-content after:border-slate-50 after:rounded-full sm:after:ml-[6.5rem] after:-translate-x-1/2 after:translate-y-1.5">
            <time className="sm:absolute left-0 translate-y-0.5 inline-flex items-center justify-center text-xs font-semibold uppercase w-20 h-6 mb-3 sm:mb-0 text-emerald-600 bg-emerald-100 rounded-full">{item.date}</time>
            <div className="text-xl font-bold text-slate-900 dark:text-white">{item.title}</div>
          </div>
          {/* Description */}
          <div className="text-slate-500">{item.content}</div>
        </div>
      ))}

    </div>
  )
}

Copy and paste the following code into your project for default variant 1.

import { Caveat } from 'next/font/google'

const caveat = Caveat({
  subsets: ['latin'],
  variable: '--font-caveat',
  display: 'swap'
})

interface TimelineItemProps {
  completed: boolean
  deliver?: boolean
  date: string
  title: string
  content: string
}

export default function VerticalTimeline02({ items }: { items: TimelineItemProps[] }) {
  return (
    <div className={`${caveat.variable} space-y-8 relative before:absolute before:inset-0 before:ml-5 before:-translate-x-px md:before:mx-auto md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-slate-300 before:to-transparent`}>

      {items.map((item, index) => (
        <div key={index} className={`relative flex items-center justify-between md:justify-normal md:odd:flex-row-reverse group ${item.completed ? 'is-active' : ''}`}>
          {/* Icon */}
          <div className="flex items-center justify-center w-10 h-10 rounded-full border border-white bg-slate-300 group-[.is-active]:bg-emerald-500 text-slate-500 group-[.is-active]:text-emerald-50 shadow shrink-0 md:order-1 md:group-odd:-translate-x-1/2 md:group-even:translate-x-1/2">
            {item.deliver ? ( 
              <svg className="fill-current" xmlns="http://www.w3.org/2000/svg" width="12" height="12">
                <path d="M12 10v2H7V8.496a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5V12H0V4.496a.5.5 0 0 1 .206-.4l5.5-4a.5.5 0 0 1 .588 0l5.5 4a.5.5 0 0 1 .206.4V10Z" />
              </svg>
            ) : (
              <svg className="fill-current" xmlns="http://www.w3.org/2000/svg" width="12" height="10">
                <path fillRule="nonzero" d="M10.422 1.257 4.655 7.025 2.553 4.923A.916.916 0 0 0 1.257 6.22l2.75 2.75a.916.916 0 0 0 1.296 0l6.415-6.416a.916.916 0 0 0-1.296-1.296Z" />
              </svg>
            )}
          </div>
          {/* Card */}
          <div className="w-[calc(100%-4rem)] md:w-[calc(50%-2.5rem)] bg-white p-4 rounded border border-slate-200 shadow">
            <div className="flex items-center justify-between space-x-2 mb-1">
              <div className="font-bold text-slate-900">{item.title}</div>
              <time className={`font-medium ${item.completed ? 'text-indigo-500' : 'text-amber-500'}`}>{!item.completed && 'Exp. '}{item.date}</time>
            </div>
            <div className="text-slate-500">{item.content}</div>
          </div>
        </div>
      ))}

    </div>
  )
}

Copy and paste the following code into your project for default variant 2.

import { Caveat } from 'next/font/google'

const caveat = Caveat({
  subsets: ['latin'],
  variable: '--font-caveat',
  display: 'swap'
})

interface TimelineItemProps {
  date: string
  author: string
  type: string
  content: string
}

export default function VerticalTimeline03({ items }: { items: TimelineItemProps[] }) {

  const typeText = (type: string): string => {
    switch (type) {
      case 'open':
        return 'opened the request'
      case 'close':
        return 'closed the request'
      case 'comment':
        return 'commented the request'
      default:
        return ''
    }
  }

  return (
    <div className={`${caveat.variable} space-y-8 relative before:absolute before:inset-0 before:ml-5 before:-translate-x-px md:before:ml-[8.75rem] md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-slate-300 before:to-transparent`}>

      {items.map((item, index) => (
        <div key={index} className="relative">
          <div className="md:flex items-center md:space-x-4 mb-3">
            <div className="flex items-center space-x-4 md:space-x-2 md:space-x-reverse">
              {/* Icon */}
              <div className="flex items-center justify-center w-10 h-10 rounded-full bg-white shadow md:order-1">
                {item.type === 'comment' ? (
                  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
                    <path className="fill-slate-300" d="M14.853 6.861C14.124 10.348 10.66 13 6.5 13c-.102 0-.201-.016-.302-.019C7.233 13.618 8.557 14 10 14c.51 0 1.003-.053 1.476-.143L14.2 15.9a.499.499 0 0 0 .8-.4v-3.515c.631-.712 1-1.566 1-2.485 0-.987-.429-1.897-1.147-2.639Z" />
                    <path className="fill-slate-500" d="M6.5 0C2.91 0 0 2.462 0 5.5c0 1.075.37 2.074 1 2.922V11.5a.5.5 0 0 0 .8.4l1.915-1.436c.845.34 1.787.536 2.785.536 3.59 0 6.5-2.462 6.5-5.5S10.09 0 6.5 0Z" />
                  </svg>
                ) : (
                  <svg className={`${item.type === 'close' ? 'fill-red-500' : 'fill-emerald-500'}`} xmlns="http://www.w3.org/2000/svg" width="16" height="16">
                    <path d="M8 0a8 8 0 1 0 8 8 8.009 8.009 0 0 0-8-8Zm0 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z" />
                  </svg>
                )}
              </div>            
              {/* Date */}
              <time className=" font-medium text-xl text-indigo-500 md:w-28">{item.date}</time>
            </div>
            {/* Title */}
            <div className="text-slate-500 ml-14"><span className="text-slate-900 font-bold">{item.author}</span> {typeText(item.type)}</div>
          </div>
          {/* Card */}
          <div className="bg-white p-4 rounded border border-slate-200 text-slate-500 shadow ml-14 md:ml-44">{item.content}</div>
        </div>
      ))}

    </div>
  )
}

Update the import paths to match your project setup.

Variants

Variant 1

Order Placed
Pretium lectus quam id leo. Urna et pharetra aliquam vestibulum morbi blandit cursus risus.
Order Shipped
Pretium lectus quam id leo. Urna et pharetra aliquam vestibulum morbi blandit cursus risus.
In Transit
Pretium lectus quam id leo. Urna et pharetra aliquam vestibulum morbi blandit cursus risus.
Out of Delivery
Pretium lectus quam id leo. Urna et pharetra aliquam vestibulum morbi blandit cursus risus.
Delivered
Pretium lectus quam id leo. Urna et pharetra aliquam vestibulum morbi blandit cursus risus.
<VerticalTimeline02/>

Variant 2

Mark Mikrol opened the request
Various versions have evolved over the years, sometimes by accident, sometimes on purpose injected humour and the like.
John Mirkovic commented the request
If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text.
Vlad Patterson commented the request
Letraset sheets containing passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Ipsum.
Mila Capentino commented the request
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
Mark Mikrol closed the request
If you are going to use a passage of Lorem Ipsum!
<VerticalTimeline03/>

Built by karthikmudunuri. The source code is available on GitHub.