Timeline
먼저 보고, 그다음 계약을 읽습니다
날짜로 묶은 활동 피드 — 좌측 dot + 수직 레일, 한국어 상대 날짜 헤더.
Component intent의도와 경계 읽기
items 를 groupBy(day/week/month/커스텀 함수) 로 묶어 최신→과거 순으로 그리는 활동 타임라인. 좌측 dot 과 이를 잇는 수직선은 CSS ::before 로만 그린다. 그룹 헤더는 relativeLabels 가 켜지면 ko-KR 상대 표기('오늘'/'어제'/'N일 전'/'이번 주'/'지난 달')로, 꺼지면 절대 날짜로 나온다. stickyHeaders 로 스크롤 중 날짜 헤더를 상단 고정하고, loadMore/hasMore/loading 으로 무한 스크롤 '더 보기'를 붙인다. item.variant 가 dot 색(success/warning/danger/info)을 정한다.
예제
SSOT에 등록된 실제 API 기준 snippet입니다. standalone 배지만 독립 실행 단위이며, fragment는 주변 state·handler 문맥을 생략합니다.
import { Timeline } from "@axe/ui";<Timeline items={[ { id: "a", date: new Date(), title: "회고 작성", content: "주간 회고 초안 완료" }, { id: "b", date: "2026-05-20", title: "Frame 배포", content: "v0.4.2 blue/green 전환", variant: "success" }, ]} groupBy="day" stickyHeaders hasMore loadMore={() => fetchMore()}/><ol class="axe-timeline axe-timeline--sticky"> <li class="axe-timeline__group"> <time class="axe-timeline__date-header" datetime="2026-05-21">오늘</time> <ol class="axe-timeline__items"> <li class="axe-timeline__item axe-timeline__item--success"> <span class="axe-timeline__rail" aria-hidden="true"> <span class="axe-timeline__dot"></span> </span> <div class="axe-timeline__body"> <div class="axe-timeline__title-row"> <span class="axe-timeline__title">Frame 배포</span> <time class="axe-timeline__time" datetime="2026-05-21T09:14">09:14</time> </div> <div class="axe-timeline__content">v0.4.2 blue/green 전환</div> </div> </li> </ol> </li></ol>Props
TSX 소스가 진실입니다. 주요 export 컴포넌트의 public API만 노출합니다.
| 이름 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
items | TimelineItem[] | 필수 | — | 타임라인 항목들. `{ id; date: Date | string; title?; content; icon?; variant? }`. date 문자열은 new Date() 로 파싱. content 만 필수, title 없으면 시각만 단독 표시. |
groupBy | "day" | "week" | "month" | ((d: Date) => string) | — | "day" | 그룹 기준. 함수를 주면 반환 문자열이 그룹 키가 되고 헤더는 절대 날짜로 표기. |
relativeLabels | boolean | — | true | 그룹 헤더를 '오늘'/'어제'/'이번 주' 등 ko-KR 상대 표기로. false 면 절대 날짜. |
stickyHeaders | boolean | — | true | 스크롤 컨테이너 안에서 날짜 헤더를 상단 고정(position: sticky). |
compact | boolean | — | false | 간격을 좁히고 dot 을 축소한 dense 모드. compact 에선 item.icon 을 그리지 않는다. |
loadMore | () => void | — | — | '더 보기' 버튼 클릭 핸들러. hasMore 와 함께 쓴다. |
hasMore | boolean | — | false | true 면 목록 하단에 '더 보기' 버튼을 렌더. |
loading | boolean | — | false | true 면 '더 보기' 대신 '불러오는 중...'(aria-live) 표시. |
...rest | Omit<React.HTMLAttributes<HTMLOListElement>, "onChange"> | — | — | className 병합, 나머지는 루트 <ol> 로 전파. ref 는 루트 ol 로 forward. |
.axe-* 클래스 계약
React 밖에서도 같은 표면을 그리는 공개 계약입니다. stable은 minor 버전 안에서 이름을 바꾸지 않습니다.
| 클래스 | 안정성 | 용도 |
|---|---|---|
.axe-timeline | stable | 루트 <ol> — 세로 그룹 스택. |
.axe-timeline--sticky | stable | 날짜 헤더 sticky-top 활성. |
.axe-timeline--compact | stable | dense 모드 — 간격/ dot 축소. |
.axe-timeline__group | stable | 한 날짜 묶음 <li>(헤더 + 항목 목록). |
.axe-timeline__date-header | stable | 그룹 날짜 헤더 <time>. |
.axe-timeline__items | stable | 그룹 안 항목들의 중첩 <ol>. |
.axe-timeline__item | stable | 항목 <li> — 레일 + 본문 2열. |
.axe-timeline__item--success | stable | dot success 색. |
.axe-timeline__item--warning | stable | dot warning 색. |
.axe-timeline__item--danger | stable | dot danger 색. |
.axe-timeline__item--info | stable | dot info 색. |
.axe-timeline__rail | stable | 좌측 dot+수직선 열(선은 ::before). aria-hidden. |
.axe-timeline__dot | stable | 항목 원형 마커(아이콘 담김). |
.axe-timeline__body | stable | 제목/시각/본문을 담는 우측 본문. |
.axe-timeline__title-row | stable | 제목 + 시각을 좌우로 놓는 줄. |
.axe-timeline__title | stable | 항목 제목 텍스트. |
.axe-timeline__time | stable | 항목 시각 <time>(HH:MM). |
.axe-timeline__time--solo | stable | 제목 없을 때 시각 단독 표기. |
.axe-timeline__content | stable | 항목 본문 영역. |
.axe-timeline__loadmore | stable | '더 보기'/로딩 줄 <li>. |
.axe-timeline__loadmore-btn | stable | '더 보기' 버튼. |
.axe-timeline__loading | stable | '불러오는 중...' 텍스트(aria-live). |
.axe-timeline__empty | stable | 항목 0개일 때 '기록이 없습니다' <li>. |
접근성
키보드, ARIA, 구현 노트를 함께 검토합니다.
시맨틱 <ol>/<li> 중첩(그룹 ol > li > time + 항목 ol > li)으로 구조를 표현. 그룹 헤더와 항목 시각은 <time datetime> 으로 머신 리더블. 좌측 rail/dot 은 aria-hidden — 장식.
'더 보기'는 진짜 <button>(loadMore 호출). 로딩 문구는 aria-live="polite" 로 알림. 항목 순서는 항상 날짜 desc(최신 먼저) 로 컴포넌트가 정렬한다. 상대 라벨은 ko-KR 고정(new Date() 기준이라 클라이언트 렌더 필요 — 그래서 "use client").