Timeline
Vertical timeline for events, order tracking, and activity feeds.
Installation#
npx @aniui/cli add timeline✓
Order confirmedMon 9:00 AM
Your order #4821 has been placed
✓
Payment receivedMon 9:01 AM
Visa ending in 4242
Preparing shipmentTue 11:30 AM
Warehouse is packing your items
In transitPending
Estimated delivery Wed
DeliveredPending
Package will arrive at your door
Web preview — components render natively on iOS & Android
import { Timeline, TimelineItem } from "@/components/ui/timeline";
export function MyScreen() {
return (
<Timeline>
<TimelineItem
title="Order placed"
description="Your order has been confirmed"
time="2:00 PM"
variant="success"
/>
<TimelineItem
title="Processing"
description="Your order is being prepared"
time="2:15 PM"
variant="default"
/>
<TimelineItem
title="Shipping"
description="Waiting for pickup"
time="Pending"
variant="muted"
isLast
/>
</Timeline>
);
}Usage#
app/index.tsx
import { Timeline, TimelineItem } from "@/components/ui/timeline";
export function MyScreen() {
return (
<Timeline>
<TimelineItem
title="Order placed"
description="Your order has been confirmed"
time="2:00 PM"
variant="success"
/>
<TimelineItem
title="Processing"
description="Your order is being prepared"
time="2:15 PM"
variant="default"
/>
<TimelineItem
title="Shipping"
description="Waiting for pickup"
time="Pending"
variant="muted"
isLast
/>
</Timeline>
);
}Props#
Timeline#
PropTypeDefault
classNamestring-childrenReact.ReactNode-TimelineItem#
PropTypeDefault
titlestring-descriptionstring-timestring-variant"default" | "success" | "destructive" | "muted""default"iconReact.ReactNode-isLastbooleanfalseclassNamestring-Accessibility#
- Vertical event timeline with
accessibilityRole="list". - Each timeline item is announced as a list item with its content.
Source#
components/ui/timeline.tsx
import React from "react";
import { View, Text } from "react-native";
import { cva, type VariantProps } from "class-variance-authority";
import { Check } from "lucide-react-native";
import { cn } from "@/lib/utils";
export interface TimelineProps extends React.ComponentPropsWithoutRef<typeof View> {
className?: string;
children?: React.ReactNode;
}
export function Timeline({ className, children, ...props }: TimelineProps) {
return (
<View className={cn("", className)} accessibilityRole="list" {...props}>
{children}
</View>
);
}
const dotVariants = cva("h-3 w-3 rounded-full", {
variants: {
variant: {
default: "bg-primary",
completed: "bg-green-500",
active: "bg-primary",
pending: "bg-muted-foreground/40",
destructive: "bg-destructive",
success: "bg-green-500",
muted: "bg-muted-foreground",
},
},
defaultVariants: { variant: "default" },
});
export interface TimelineItemProps
extends React.ComponentPropsWithoutRef<typeof View>,
VariantProps<typeof dotVariants> {
className?: string;
title: string;
description?: string;
time?: string;
icon?: React.ReactNode;
isLast?: boolean;
}
export function TimelineItem({
variant,
className,
title,
description,
time,
icon,
isLast,
...props
}: TimelineItemProps) {
const isActive = variant === "active";
return (
<View className={cn("flex-row", className)} accessibilityRole="listitem" {...props}>
{/* Dot + Line */}
<View className="items-center w-6" style={{ paddingTop: 4 }}>
{icon ?? (
<View className={cn(dotVariants({ variant }), isActive && "border-2 border-primary/30")}>
{variant === "completed" && (
<View className="flex-1 items-center justify-center">
<Check size={8} color="#ffffff" strokeWidth={3} />
</View>
)}
</View>
)}
{!isLast && <View className="flex-1 w-px bg-border mt-1.5 mb-0" />}
</View>
{/* Content */}
<View className={cn("flex-1 ms-3 pb-6", isLast && "pb-0")}>
<View className="flex-row items-start justify-between gap-2">
<Text className={cn("text-sm font-medium flex-1", variant === "pending" ? "text-muted-foreground" : "text-foreground")}>{title}</Text>
{time && <Text className="text-[11px] text-muted-foreground">{time}</Text>}
</View>
{description && (
<Text className={cn("text-[13px] leading-5 mt-1", variant === "pending" ? "text-muted-foreground/60" : "text-muted-foreground")}>{description}</Text>
)}
</View>
</View>
);
}

