패턴
목록과 상세
상세는 URL ?item= 하나가 원천. 1024 이상 split, 미만 push. 닫으면 같은 행으로, 행이 사라졌으면 다음 행 → 이전 행 → 목록 제목.
URL이 상태다
상세의 유일한 상태 원천은 URL ?item=<id>다. 새로고침·공유·뒤로 가기로 같은 화면이 다시 나온다.
| 키 | 뜻 | 기록 방식 |
|---|---|---|
item | 열린 상세 | pushState. 목록에서 열었으면 닫기 = history.back(), 직접 들어왔으면 replaceState로 키 제거 |
q | 검색어 | replaceState, 300ms 디바운스 |
scope · view · filter | 범위 캡슐 · 분할 선택 · 필터 칩 | replaceState |
tab | 상세 안 탭 | replaceState |
page | 페이지 이동 | pushState (이동이다) |
source | <1024의 원문 미리보기 push | pushState |
URL에 넣지 않는 것: Menu·Popover·Tooltip·Toast 열림, Sheet·Modal 열림, 폼 초안(sessionStorage), hover. 목록 스크롤 위치는 URL을 키로 sessionStorage에 두고 상세를 닫으면 복원한다.
split과 push
- 1024px 이상은 split(목록 360–400 + 상세 최대 720), 미만은 push(오른쪽에서 move).
- split에서 상세 교체는 모션 없이 즉시. ↑/↓로 빠르게 넘길 때 깜빡이지 않게.
- 상세를 열면 초점은 상세 h1(tabindex=-1). 닫으면 스크롤·초점·검색어가 돌아온다.
- 200–400% 확대로 split이 push로 바뀌어도 초점은 같은 요소에 남는다. sticky 헤더가 초점을 가리지 않게 scroll-padding(2.4.11).
- Sheet는 동의·확인 같은 짧은 작업에만. 상세에는 쓰지 않는다.
초점 복귀 데모
실제 컴포넌트: 목록 → 상세 → 닫기 (resolveReturnFocus)
/records?q=roadmap
기록
행을 고르면 상세가 여기 열린다(≥1024 split). 좁은 화면에서는 같은 URL로 push.
새 데이터는 끼워 넣지 않는다
- 이렇게목록 맨 위에 있으면 새 행을 위에서부터 추가한다. 스크롤한 뒤에는 “새 기록 N개” 칩을 띄운다. 칩을 누르면 맨 위로 스크롤하고 첫 새 행에 초점.
- 이렇게 하지 않기보고 있는 목록에 행을 끼워 넣지 않는다. 사용자가 보던 위치를 잃는다.
- 이렇게 하지 않기행이 사라질 때 아래 행들을 미끄러지게 하지 않는다. 이유는 토스트의 “되돌리기”가 설명한다.