Timeline
WhereUIลำดับเหตุการณ์แนวตั้ง เช่น ประวัติการอนุมัติ หรือความเคลื่อนไหวของเอกสาร แต่ละรายการมีไอคอน ชื่อเหตุการณ์ ผู้กระทำ และเวลา
- ส่งคำขอลากิจโดย สมชาย ใจดี · 11 พ.ย. 2569 09:15
- หัวหน้างานอนุมัติโดย สมพร ศรีสุข · 11 พ.ย. 2569 14:32
- HR บันทึกลงระบบบัญชีวันลาโดย มาลี รักงาน · 12 พ.ย. 2569 10:05
ติดตั้ง
Terminal
pnpm dlx shadcn@latest add @whereui/timelineต้องผูก registry และติดตั้ง @whereui/theme นำหน้าเสมอเมื่อติดตั้งครั้งแรก
การใช้งาน
import { Timeline, TimelineItem } from "@/components/ui/timeline"<Timeline> <TimelineItem title="ส่งคำขอ" meta="โดย สมชาย ใจดี · 11 พ.ย. 2569 09:15" /></Timeline>ตัวอย่างเพิ่มเติม
ไอคอนและคำอธิบาย
- ส่งเอกสารเบิกค่าเดินทางโดย สมหญิง ขยันมาก · 10 พ.ย. 2569 16:20แนบใบเสร็จ 3 รายการ รวม 2,480 บาท
- ฝ่ายบัญชีตรวจสอบเอกสารโดย วิภา ตรวจดี · 12 พ.ย. 2569 11:00เอกสารครบถ้วน รอผู้มีอำนาจอนุมัติลงนาม
- อนุมัติการเบิกจ่ายโดย กรรมการ ธนากร · 13 พ.ย. 2569 09:40
Props
| prop | type | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
| icon | React.ReactNode | — | ไอคอนเหตุการณ์อยู่ในวงกลมพื้น muted — ถ้าไม่ใส่จะแสดงจุดกลมเล็ก |
| title | React.ReactNode | — | ชื่อเหตุการณ์ เช่น "หัวหน้าอนุมัติ" |
| meta | React.ReactNode | — | บรรทัดรองสีเทา เช่น ผู้กระทำและเวลา |
| description | React.ReactNode | — | รายละเอียดเพิ่มเติมใต้ชื่อเหตุการณ์ |
| children | React.ReactNode | — | เนื้อหาพิเศษท้ายรายการ เช่น StatusPill |
ข้อควรรู้
- เส้นเชื่อมระหว่างรายการซ่อนอัตโนมัติที่รายการสุดท้าย
- Timeline เป็น <ol> ใช้ semantic ร่วมกับโปรแกรมอ่านหน้าจอได้ทันที
ซอร์สโค้ด
components/ui/timeline.tsx
import * as React from "react"import { cn } from "cn"function Timeline({ className, ...props }: React.ComponentProps<"ol">) { return ( <ol data-slot="timeline" className={cn("flex flex-col", className)} {...props} /> )}function TimelineItem({ className, icon, title, meta, description, children, ...props}: React.ComponentProps<"li"> & { /** ไอคอนเหตุการณ์ ถ้าไม่ใส่จะแสดงจุดกลม */ icon?: React.ReactNode /** ชื่อเหตุการณ์ เช่น "อนุมัติคำขอ" */ title?: React.ReactNode /** บรรทัดรอง เช่น ผู้กระทำและเวลา */ meta?: React.ReactNode /** รายละเอียดเพิ่มเติม */ description?: React.ReactNode}) { return ( <li data-slot="timeline-item" className={cn( "relative flex gap-3 pb-6 last:pb-0 last:[&>[data-slot=timeline-rail]]:hidden", className )} {...props} > <span data-slot="timeline-rail" aria-hidden="true" className="absolute top-9 bottom-0 left-4 w-px bg-border" /> <span data-slot="timeline-icon" className="relative z-1 flex size-8 shrink-0 items-center justify-center" > {icon ? ( <span className="grid size-8 place-items-center rounded-full bg-muted text-foreground [&_svg]:size-4"> {icon} </span> ) : ( <span className="size-2 rounded-full bg-foreground/30" /> )} </span> <div data-slot="timeline-content" className="min-w-0 flex-1 pt-0.5" > {title ? ( <div className="text-sm leading-snug font-medium">{title}</div> ) : null} {meta ? ( <div className="mt-0.5 text-xs text-muted-foreground">{meta}</div> ) : null} {description ? ( <div className="mt-1 text-sm text-muted-foreground"> {description} </div> ) : null} {children} </div> </li> )}export { Timeline, TimelineItem }