Timeline

Timeline visualizes a series of chained events.

Usage#

import { Timeline } from 'primereact/timeline';
<Timeline>
    <Timeline.Event>
        <Timeline.Opposite />
        <Timeline.Separator>
            <Timeline.Marker />
            <Timeline.Connector />
        </Timeline.Separator>
        <Timeline.Content />
    </Timeline.Event>
</Timeline>

Examples#

Basic#

Ordered
Processing
Shipped
Delivered
basic-demo.tsx
'use client';

import { Timeline } from 'primereact/timeline';

export default function BasicDemo() {
    const events = [{ status: 'Ordered' }, { status: 'Processing' }, { status: 'Shipped' }, { status: 'Delivered' }];

    return (
        <div>
            <Timeline>
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event.status}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
        </div>
    );
}

Alignment#

Content location relative the line is defined with the align property.

Ordered
Processing
Shipped
Delivered
Ordered
Processing
Shipped
Delivered
Ordered
Processing
Shipped
Delivered
alignment-demo.tsx
'use client';

import { Timeline } from 'primereact/timeline';

export default function AlignmentDemo() {
    const events = [{ status: 'Ordered' }, { status: 'Processing' }, { status: 'Shipped' }, { status: 'Delivered' }];

    return (
        <div className="flex flex-wrap gap-12">
            <Timeline className="w-full md:w-80">
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event.status}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
            <Timeline align="right" className="w-full md:w-80">
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event.status}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
            <Timeline align="alternate" className="w-full md:w-80">
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event.status}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
        </div>
    );
}

Opposite#

Additional content at the other side of the line can be provided with the opposite property.

15/10/2020 10:30
Ordered
15/10/2020 14:00
Processing
15/10/2020 16:15
Shipped
16/10/2020 10:00
Delivered
opposite-demo.tsx
'use client';

import { Timeline } from 'primereact/timeline';

export default function OppositeDemo() {
    const events = [
        { status: 'Ordered', date: '15/10/2020 10:30' },
        { status: 'Processing', date: '15/10/2020 14:00' },
        { status: 'Shipped', date: '15/10/2020 16:15' },
        { status: 'Delivered', date: '16/10/2020 10:00' }
    ];

    return (
        <div>
            <Timeline>
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite>
                            <small className="text-surface-500 dark:text-surface-400">{event.date}</small>
                        </Timeline.Opposite>
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event.status}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
        </div>
    );
}

Horizontal#

TimeLine orientation is controlled with the orientation property, default is vertical having horizontal as the alternative.

2020
2021
2022
2023
2020
2021
2022
2023
 
2020
 
2021
 
2022
 
2023
horizontal-demo.tsx
'use client';

import { Timeline } from 'primereact/timeline';

export default function HorizontalDemo() {
    const events = ['2020', '2021', '2022', '2023'];

    return (
        <div className="flex flex-col gap-4">
            <Timeline orientation="horizontal" align="top">
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
            <Timeline orientation="horizontal" align="bottom">
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
            <Timeline orientation="horizontal" align="alternate">
                {events.map((event, index) => (
                    <Timeline.Event key={index}>
                        <Timeline.Opposite>&nbsp;</Timeline.Opposite>
                        <Timeline.Separator>
                            <Timeline.Marker />
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content>{event}</Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
        </div>
    );
}

Custom#

Sample implementation with custom content and styled markers.

Ordered
15/10/2020 10:30
Ordered

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!

Processing
15/10/2020 14:00

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!

Shipped
15/10/2020 16:15

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!

Delivered
16/10/2020 10:00

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!

custom-demo.tsx
'use client';

import { Button } from 'primereact/button';
import { Card } from 'primereact/card';
import { Timeline } from 'primereact/timeline';

export default function CustomDemo() {
    const events = [
        { status: 'Ordered', date: '15/10/2020 10:30', icon: 'pi pi-shopping-cart', color: '#9C27B0', image: 'game-controller.jpg' },
        { status: 'Processing', date: '15/10/2020 14:00', icon: 'pi pi-cog', color: '#673AB7' },
        { status: 'Shipped', date: '15/10/2020 16:15', icon: 'pi pi-shopping-cart', color: '#FF9800' },
        { status: 'Delivered', date: '16/10/2020 10:00', icon: 'pi pi-check', color: '#607D8B' }
    ];

    return (
        <div>
            <Timeline align="alternate">
                {events.map((event, index) => (
                    <Timeline.Event key={index} className={index % 2 === 1 ? 'max-[960px]:flex-row' : undefined}>
                        <Timeline.Opposite />
                        <Timeline.Separator>
                            <span
                                className={[
                                    'flex w-8 h-8 items-center justify-center rounded-full z-10 shadow-sm',
                                    index !== events.length - 1 ? 'text-white bg-primary' : ''
                                ].join(' ')}
                            >
                                <i className={event.icon}></i>
                            </span>
                            {index !== events.length - 1 && <Timeline.Connector />}
                        </Timeline.Separator>
                        <Timeline.Content className={index % 2 === 1 ? 'max-[960px]:!text-left' : undefined}>
                            <Card className="mt-4">
                                <Card.Body>
                                    <Card.Caption>
                                        <Card.Title>{event.status}</Card.Title>
                                        <Card.Subtitle>{event.date}</Card.Subtitle>
                                    </Card.Caption>
                                    <Card.Content>
                                        {event.image && (
                                            <img
                                                src={`https://primefaces.org/cdn/primevue/images/product/${event.image}`}
                                                alt={event.status}
                                                width="200"
                                                className="shadow-sm"
                                            />
                                        )}
                                        <p>
                                            Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae
                                            numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse,
                                            cupiditate neque quas!
                                        </p>
                                        <Button variant="text">Read more</Button>
                                    </Card.Content>
                                </Card.Body>
                            </Card>
                        </Timeline.Content>
                    </Timeline.Event>
                ))}
            </Timeline>
        </div>
    );
}