Marker
A step in an activity timeline or between messages, in the code voice. A glyph and words, a divider between days, a heading over a run of steps, or work still going. Pending runs the yellow segment under the words, never a spinner.
Loading the live example…
"use client"
import { Package, Phone, Truck } from "lucide-react"
import { useEffect, useRef, useState } from "react"
import { Button } from "@/components/keyline/ui/button"
import { Marker, MarkerContent, MarkerIcon } from "@/components/keyline/ui/marker"
import { Status } from "@/components/keyline/ui/status"
const PHONE = <Phone size={16} aria-hidden="true" />
const BOX = <Package size={16} aria-hidden="true" />
const TRUCK = <Truck size={16} aria-hidden="true" />
type Step = "idle" | "picking" | "picked"
export function OrderActivity() {
const [step, setStep] = useState<Step>("idle")
const timer = useRef<ReturnType<typeof setTimeout>>(undefined)
useEffect(() => () => clearTimeout(timer.current), [])
const send = () => {
setStep("picking")
timer.current = setTimeout(() => setStep("picked"), 2400)
}
return (
<div className="grid max-w-[460px] gap-3">
<Marker variant="border">
<MarkerContent>DM-4107 · Lackawanna County</MarkerContent>
</Marker>
<Marker variant="separator">
<MarkerContent>Yesterday</MarkerContent>
</Marker>
<Marker>
<MarkerIcon>{PHONE}</MarkerIcon>
<MarkerContent>Dwight took the order by phone: 120 cases</MarkerContent>
</Marker>
<Marker variant="separator">
<MarkerContent>Today</MarkerContent>
</Marker>
<Marker>
<MarkerIcon>{BOX}</MarkerIcon>
<MarkerContent>Angela approved the credit check</MarkerContent>
</Marker>
{step !== "idle" ? (
<Marker pending={step === "picking"}>
<MarkerIcon>{step === "picking" ? TRUCK : <Status kind="done" />}</MarkerIcon>
<MarkerContent>{step === "picking" ? "Darryl's team is picking 120 cases…" : "Picked and on the truck for Thursday"}</MarkerContent>
</Marker>
) : null}
<Button className="mt-2 justify-self-start" disabled={step !== "idle"} onClick={send}>
{step === "idle" ? "Send to the warehouse" : "Sent to the warehouse"}
</Button>
</div>
)
}Installation
npx shadcn@latest add @keyline-ui/markerRun it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.
Usage
import { Marker, MarkerContent, MarkerIcon } from "@/components/keyline/ui/marker"<Marker variant="separator">
<MarkerContent>Today</MarkerContent>
</Marker>
<Marker pending={picking}>
<MarkerIcon>{TruckIcon}</MarkerIcon>
<MarkerContent>Darryl's team is picking 120 cases…</MarkerContent>
</Marker>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "separator" | "border" | Default "default" | A step; words between two seams, such as a day; or a heading with a keyline under it. |
pending | boolean | Default false | Work in progress. The marker becomes a polite status, so the change is announced. Remove it when the step is done. |
MarkerIcon | ReactNode | Default — | A 16px glyph cell, hidden from screen readers. |
MarkerContent | ReactNode | Default — | The words. |
A marker is a div; a separator marker has the separator role.