ScrollArea
경계가 분명한 콘텐츠 영역에 일관된 스크롤 동작을 제공합니다.
목적
ScrollArea는 제한된 영역 안의 긴 콘텐츠를 native scroll 동작과 일관된 scrollbar로 탐색하게 한다. 페이지 전체 흐름을 자르기보다 독립적으로 scroll되어야 하는 목록이나 panel에만 사용한다.
선택 기준
- command 결과, sidebar content, 제한 높이의 기록처럼 독립 scroll 영역이 필요할 때 사용한다.
- 일반 문서와 페이지 본문은 브라우저의 page scroll을 유지한다.
- 중요한 콘텐츠를 작은 고정 영역에 숨기기 위한 수단으로 사용하지 않는다.
- 가로로 비교해야 하는 Table은 Table이 제공하는 overflow wrapper를 우선한다.
구조
ScrollArea가 root와 viewport, 기본 vertical ScrollBar, corner를 함께 만든다. 가로 scroll이 필요한 경우 children 끝에 ScrollBar orientation="horizontal"을 추가한다. ScrollArea 자체에 높이나 너비를 지정해야 viewport의 scroll 범위가 만들어진다.
변형과 크기
별도 variant나 size prop은 없다. 기본 vertical scrollbar 너비와 horizontal scrollbar 높이는 10px이고 thumb는 border semantic 색과 둥근 형태를 사용한다. ScrollBar의 orientation 기본값은 vertical이며 horizontal도 지원한다.
상태와 동작
wheel, trackpad, touch, keyboard 등 platform scroll 동작을 유지한다. thumb의 크기와 위치는 콘텐츠 양에 따라 바뀐다. ScrollArea는 loading, end reached, virtualized 상태를 제공하지 않는다. 데이터 추가나 무한 scroll이 필요하면 제품이 결과 변화와 다음 로딩 상태를 별도로 관리한다.
콘텐츠
사용자가 영역이 scroll 가능하다는 것을 내용 일부와 scrollbar로 자연스럽게 이해할 수 있게 한다. 영역 끝에 중요한 action을 숨기지 않는다. 긴 목록에는 현재 filter, 결과 수, 빈 상태를 영역 바깥이나 시작점에 명확히 표시한다.
접근성
ScrollArea 안의 interactive element는 DOM 순서대로 keyboard 접근이 가능해야 한다. scroll 영역 자체에 의미 있는 label이 필요하면 주변 heading과 aria-labelledby 같은 관계를 제품에서 구성한다. keyboard focus가 들어왔을 때 visible item이 viewport 밖에 남지 않는지 확인한다.
좁은 화면과 긴 콘텐츠
좁은 화면에서 내부 scroll과 page scroll이 같은 방향으로 경쟁하지 않게 한다. 가로 scroll은 데이터 비교처럼 정보 보존이 더 중요한 경우에만 허용하고, 가능하면 핵심 필드를 세로 record 구조로 바꾼다. touch target이 scrollbar 근처에서 너무 작아지지 않게 한다.
공개 API
ScrollArea: root props를 전달하며 vertical scrollbar와 corner를 자동 렌더링한다.ScrollBar:orientation="vertical" | "horizontal"; 기본값은vertical
Viewport와 thumb는 별도 public export가 아니다.
예제
import { ScrollArea, Separator } from '@classum/dot-design-system/ui';
const events = ['초안 저장', '검증 통과', '검토 요청', '담당자 변경'];
export function HistoryList() {
return (
<ScrollArea className="h-56 rounded-md border">
<div className="p-4">
<h2 className="mb-3 font-semibold">최근 변경</h2>
{events.map((event, index) => (
<div key={`${event}-${index}`}>
<p className="py-3 text-sm">{event}</p>
{index < events.length - 1 ? <Separator /> : null}
</div>
))}
</div>
</ScrollArea>
);
}피해야 할 사용
- 페이지 본문 전체를 ScrollArea로 감싸지 않는다.
- 높이 제한 없이 ScrollArea를 넣고 scroll이 생길 것으로 기대하지 않는다.
- 같은 방향의 nested scroll 영역을 여러 단계 만들지 않는다.
- 끝에 도달해야만 중요한 주 행동을 발견하게 하지 않는다.
- 좁은 화면에서 표의 모든 열을 무조건 가로 scroll로 유지하지 않는다.