# Flight Itinerary

> Flight itinerary timeline with local times as titles, airport codes in Geist Mono tags, a layover row between legs, and a plane mark with a Boarding badge on the current leg.

A shadcn/ui block from the [@01orbital](https://01orbital.dev/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/01orbital/flight-itinerary).

- Page, with a live preview: https://shadcn.exchange/r/01orbital/flight-itinerary
- Screenshot: https://shadcn.exchange/shot/01orbital/flight-itinerary/light.png
- Registry item: https://01orbital.dev/r/flight-itinerary.json
- Categories: timeline
- Listed: 2026-11-01, source last changed 2026-11-01

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/01orbital/flight-itinerary.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@phosphor-icons/react`
- Registry items: `@01orbital/badge`, `@01orbital/font-geist-mono`, `@01orbital/timeline`

## Files

### `blocks/timeline/flight-itinerary/index.tsx`

```tsx
import { AirplaneTiltIcon } from "@phosphor-icons/react/dist/ssr"

import {
  Timeline,
  TimelineContent,
  TimelineDescription,
  TimelineIndicator,
  TimelineItem,
  TimelineLabel,
  TimelineTitle,
} from "@/components/editorial/timeline"
import { Badge } from "@/components/ui/badge"

// The copy: change text here, not in the markup.
const COPY = {
  title: "Lisbon to Tokyo",
  body: "Thursday 30 October · 1 stop · 15h 40m · local times",
  boarding: "Boarding",
  layover: "Layover",
} as const

const LEGS = [
  {
    time: "09:35",
    code: "LIS",
    place: "Lisbon Humberto Delgado",
    detail: "Terminal 1 · Gate 14",
    current: true,
  },
  {
    time: "13:50",
    code: "FRA",
    place: "Frankfurt",
    detail: "Arrives · Terminal 1",
    layover: "2h 10m",
  },
  {
    time: "16:00",
    code: "FRA",
    place: "Frankfurt",
    detail: "Terminal 1 · Gate Z23",
  },
  {
    time: "10:15 +1",
    code: "HND",
    place: "Tokyo Haneda",
    detail: "Arrives Friday · Terminal 3",
  },
] as const

// A trip is one subject in time order: the time is the title, the airport
// code a mono tag, the layover a muted row between legs. The plane marks the
// leg you are on.
export default function FlightItinerary() {
  return (
    <section className="mx-auto w-full max-w-md">
      <header className="mb-6">
        <h2 className="text-lg font-semibold tracking-tight">{COPY.title}</h2>
        <p className="mt-1 text-sm text-muted-foreground">{COPY.body}</p>
      </header>
      <Timeline className="[--timeline-lh:1.5rem]">
        {LEGS.map((l) => {
          const current = "current" in l
          return (
            <TimelineItem key={l.time + l.code}>
              {current ? (
                <TimelineIndicator>
                  <span className="flex size-4 items-center justify-center rounded-full bg-foreground text-background">
                    <AirplaneTiltIcon
                      className="size-2.5"
                      weight="fill"
                      aria-hidden
                    />
                  </span>
                </TimelineIndicator>
              ) : (
                <TimelineIndicator className="border-border [&_[data-slot=timeline-dot]]:bg-muted-foreground/60" />
              )}
              <TimelineContent className="pb-7">
                <div className="flex items-center gap-3">
                  <TimelineTitle className="text-base leading-6 tabular-nums">
                    {l.time}
                  </TimelineTitle>
                  <code className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs">
                    {l.code}
                  </code>
                  {current && <Badge>{COPY.boarding}</Badge>}
                </div>
                <TimelineDescription className="mt-0.5 text-foreground">
                  {l.place}
                </TimelineDescription>
                <TimelineLabel className="mt-0.5">{l.detail}</TimelineLabel>
                {"layover" in l && (
                  <TimelineLabel className="mt-3 rounded-md bg-muted px-2 py-1">
                    {COPY.layover} · {l.layover}
                  </TimelineLabel>
                )}
              </TimelineContent>
            </TimelineItem>
          )
        })}
      </Timeline>
    </section>
  )
}
```
