Campfire
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 timeline

Or with any shadcn-compatible CLI:

bunx shadcn@latest add https://campfire-deck.vercel.app/r/timeline.json

Copy both files. They import cn from @/lib/utils — scaffolded by camp init, or camp add utils:

components/timeline.tsx
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}
    />
  );
}
components/timeline-item.tsx
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:

slides/05-roadmap.mdx
---
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

On this page