Timeline Rail
shadcn-extras/timeline-railFreeComponent
Horizontal timeline with dots, labels and captions.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/NayanDevLab/shadcn-extras/dev/public/c/timeline-rail.jsonSource
1'use client';23import * as React from 'react';4import { cn } from '@/lib/utils';56type AnchorOrButton =7 | ({8 href: string;9 onClick?: never;10 } & React.AnchorHTMLAttributes<HTMLAnchorElement>)11 | ({12 href?: undefined;13 onClick?: React.MouseEventHandler<HTMLButtonElement>;14 } & React.ButtonHTMLAttributes<HTMLButtonElement>);1516export type TimelineItem = {17 /** Main small label shown near the dot (e.g., “headset”) */18 label?: string;19 /** Secondary label shown under the rail (e.g., “1910”) */20 caption?: string;21 /** Is this item emphasized (darker dot/rail before it) */22 active?: boolean;23} & AnchorOrButton;2425export type TimelineRailProps = {26 /** Items in left→right order */27 items: TimelineItem[];2829 /** Size density (dot size + vertical offsets) */30 size?: 'sm' | 'md';3132 /** Visually emphasize the rail up to the last `active` item */33 emphasizeActiveTrail?: boolean;3435 /** Angle for the top labels (deg). use 0 for straight text. */36 labelAngle?: number;3738 /** Layout spacing between dots (Tailwind gap classes allowed). */39 gapClassName?: string;4041 /** Visual customization */42 lineColorClass?: string; // rail color43 lineThickness?: number; // pixels44 dotClass?: string; // dot color/class45 dotActiveClass?: string; // active dot color/class4647 /** Slots for precise control */48 className?: string; // root49 railClassName?: string; // the line element50 itemClassName?: string; // <li>51 labelClassName?: string; // top tiny label52 captionClassName?: string; // bottom caption5354 /** Optional renderers to fully control content */55 renderLabel?: (item: TimelineItem, index: number) => React.ReactNode;56 renderCaption?: (item: TimelineItem, index: number) => React.ReactNode;57};5859/** SRP: purely visual timeline rail. No data fetching or state kept here. */60export default function TimelineRail({61 items,62 size = 'md',63 emphasizeActiveTrail = true,64 labelAngle = 45,65 gapClassName = 'gap-14',66 lineColorClass = 'bg-zinc-300 dark:bg-zinc-700',67 lineThickness = 6,68 dotClass = 'bg-zinc-400 dark:bg-zinc-600',69 dotActiveClass = 'bg-zinc-900 dark:bg-zinc-100',70 className,71 railClassName,72 itemClassName,73 labelClassName,74 captionClassName,75 renderLabel,76 renderCaption,77}: TimelineRailProps) {78 // compute last active index (for emphasized rail)79 const lastActive = React.useMemo(() => {80 let idx = -1;81 items.forEach((it, i) => {82 if (it.active) idx = i;83 });84 return idx;85 }, [items]);8687// … truncated
Files it writes
More from shadcn-extras
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Image Gridanimated-image-grid | shadcn-extras | Components | Free | no deps · 3 files | |
| Blog Card Fourblog-card-four | shadcn-extras | Components | Free | 1 dep | |
| Blog Card Oneblog-card-one | shadcn-extras | Components | Free | no deps | |
| Blog Card Threeblog-card-three | shadcn-extras | Components | Free | 1 dep | |
| Blog Card Twoblog-card-two | shadcn-extras | Components | Free | 1 dep | |
| Bulb Iconbulb-icon | shadcn-extras | Components | Free | 2 deps | |
| Chevron Stepschevron-steps | shadcn-extras | Components | Free | no deps | |
| Circular Gallerycircular-gallery | shadcn-extras | Components | Free | no deps · 3 files |
