Splitter
먼저 보고, 그다음 계약을 읽습니다
키보드·a11y 갖춘 2-pane 리사이즈 컨테이너.
Component intent의도와 경계 읽기
두 pane 을 가로(좌/우) 또는 세로(상/하)로 나누고 사이 핸들로 크기를 조절한다. Blueprint 의 마우스 전용 ResizeHandle 을 role="separator" + 화살표/Home/End 키보드 + 터치 히트영역 확장으로 일반화했다. controlled(size + onSizeChange)와 uncontrolled(defaultSize) 를 모두 지원하며, 드래그 중에는 rAF 로 첫 pane DOM 에 직접 써 리렌더를 억제하고 커밋은 pointerup 1회만 수행한다.
예제
SSOT에 등록된 실제 API 기준 snippet입니다. standalone 배지만 독립 실행 단위이며, fragment는 주변 state·handler 문맥을 생략합니다.
import { Splitter } from "@axe/ui";<Splitter orientation="horizontal" defaultSize="40%" minSize={200}> <nav>목록</nav> <main>상세</main></Splitter>import { Splitter } from "@axe/ui";import { useState } from "react";function Panes() { const [w, setW] = useState(320); return ( <Splitter orientation="horizontal" size={w} onSizeChange={setW} minSize={160}> <aside>사이드</aside> <section>본문</section> </Splitter> );}Props
TSX 소스가 진실입니다. 주요 export 컴포넌트의 public API만 노출합니다.
| 이름 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
orientation | "horizontal" | "vertical" | 필수 | — | pane 배치 축. horizontal = 좌/우, vertical = 상/하. |
defaultSize | number | string | — | "50%" | uncontrolled 초기 크기. number=px, string=CSS length(예 "50%"). string 이면 mount 후 컨테이너 측정으로 px 환산. |
size | number | — | — | controlled px. 지정 시 defaultSize 무시 — 크기를 소비자가 소유. |
onSizeChange | (px: number) => void | — | — | 크기 확정 시 호출. 키보드는 즉시, 드래그는 pointerup 에서 1회. controlled 소비자는 여기서 size 를 갱신. |
minSize | number | — | 80 | 첫 pane 최소 px. |
maxSize | number | — | — | 첫 pane 최대 px. 미지정 시 컨테이너 측정값 − minSize 로 자동 산출. |
children | [React.ReactNode, React.ReactNode] | 필수 | — | 정확히 2개. [0]=첫 pane(크기 제어 대상), [1]=둘째 pane(남는 공간). |
...rest | Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "onChange"> | — | — | className 은 병합, 나머지는 루트 div 로 전파. |
.axe-* 클래스 계약
React 밖에서도 같은 표면을 그리는 공개 계약입니다. stable은 minor 버전 안에서 이름을 바꾸지 않습니다.
| 클래스 | 안정성 | 용도 |
|---|---|---|
.axe-splitter | stable | 루트 flex 컨테이너(width/height 100%, min 0). |
.axe-splitter--horizontal | stable | flex-direction:row(좌/우 분할). |
.axe-splitter--vertical | stable | flex-direction:column(상/하 분할). |
.axe-splitter__pane | stable | pane 공통 — min 0 + overflow:auto. |
.axe-splitter__pane--second | stable | 둘째 pane — flex:1 1 auto 로 남는 공간 차지(첫 pane 은 인라인 width/height 로 크기 고정). |
.axe-splitter__handle | stable | 드래그/포커스 핸들(role=separator). 시각 6px + ::before 26px 히트영역(WCAG 2.5.5). hover/focus 시 accent. |
.axe-splitter__handle-bar | stable | 핸들 중앙 시각 바(2×36px, aria-hidden 장식). |
접근성
키보드, ARIA, 구현 노트를 함께 검토합니다.
- ←/→(horizontal) 또는 ↑/↓(vertical) — 핸들 포커스 시 ±5px
- Shift + 화살표 — ±20px
- Home — 첫 pane 을 minSize 로
- End — 첫 pane 을 maxSize(지정/자동)로
핸들은 role="separator" + tabIndex 0. aria-orientation 은 핸들 바의 축 기준이라 orientation 과 반대(좌우 분할=vertical 바, 상하 분할=horizontal 바). aria-valuenow/valuemin/valuemax = 첫 pane px, aria-valuetext 는 사람이 읽는 "Left/Top pane Npx of Mpx (P%)", aria-label="Resize panels". 시각 바(__handle-bar)는 aria-hidden.
포인터 캡처 드래그는 rAF 로 프레임당 1회 첫 pane DOM 에 직접 쓰고, state/onSizeChange 커밋은 pointerup 1회(고주사율 기기 과렌더 방지). prefers-reduced-motion 에서 핸들 트랜지션 제거. 알려진 한계: controlled 소비자가 onSizeChange 를 무시(size prop 유지)하고 리렌더도 없으면 드래그 잔여 px 가 남을 수 있음.