Registry
Timeline
A horizontal sequence of milestones for roadmap slides.
<Timeline>
<TimelineItem period="Q1" heading="Prototype">
Filesystem runtime and live shell.
</TimelineItem>
<TimelineItem period="Q2" heading="Registry">
shadcn-compatible blocks and primitives.
</TimelineItem>
<TimelineItem period="Q3" heading="Kits">
Starter packs that compose blocks.
</TimelineItem>
<TimelineItem period="Q4" heading="v1">
Stable layout contract.
</TimelineItem>
</Timeline>Installation
Installs Timeline and TimelineItem together.
camp add timelineOr with any shadcn-compatible CLI:
bunx shadcn@latest add https://campfire-deck.vercel.app/r/timeline.jsonCopy both files. They import cn from @/lib/utils — scaffolded by
camp init, or camp add utils:
import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";
export type TimelineProps = ComponentProps<"ol">;
/** A horizontal sequence of milestones. Pair with TimelineItem. */
export default function Timeline({ className, ...props }: TimelineProps) {
return (
<ol
className={cn("flex w-full items-start", className)}
data-slot="timeline"
{...props}
/>
);
}import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";
export type TimelineItemProps = ComponentProps<"li"> & {
/** Milestone heading. */
heading: string;
/** Optional time marker, e.g. "Q3 2026". */
period?: string;
};
/** A single milestone on a Timeline. */
export default function TimelineItem({
heading,
period,
className,
children,
...props
}: TimelineItemProps) {
return (
<li
className={cn("group flex flex-1 flex-col gap-5", className)}
data-slot="timeline-item"
{...props}
>
<div className="flex w-full items-center gap-3">
<span
className="size-4 shrink-0 rounded-full bg-primary"
data-slot="timeline-item-marker"
/>
<span className="h-0.5 flex-1 rounded bg-foreground/15 group-last:hidden" />
</div>
<div className="flex flex-col gap-1 pr-10">
{period ? (
<span
className="font-medium text-lg text-primary uppercase tracking-wide"
data-slot="timeline-item-period"
>
{period}
</span>
) : null}
<span
className="font-heading font-semibold text-2xl tracking-tight"
data-slot="timeline-item-heading"
>
{heading}
</span>
{children ? (
<div
className="text-lg leading-relaxed opacity-70"
data-slot="timeline-item-detail"
>
{children}
</div>
) : null}
</div>
</li>
);
}Usage
Items share the row equally; the connecting line stops at the last marker:
---
title: Roadmap
---
## Roadmap
<Timeline>
<TimelineItem period="Now" heading="Private beta" />
<TimelineItem period="Q3" heading="Public launch" />
<TimelineItem period="Q4" heading="Enterprise" />
</Timeline>API Reference
Timeline extends ComponentProps<"ol"> and exposes
data-slot="timeline"; it only lays out its items.
TimelineItem extends ComponentProps<"li"> — native props are forwarded
and className is merged last. Parts expose data-slot="timeline-item",
timeline-item-marker, timeline-item-period, timeline-item-heading,
and timeline-item-detail.
Prop
Type