[회고록] 클릭했는데 아무 반응이 없다 — MUI Dialog 안 ColorPicker 디버깅기
발단
MUI Dialog 안에서 react-color의 SketchPicker를 사용하고 있었다. 색상 피커는 잘 열리는데, hex/RGB input을 클릭해도 커서가 생기지 않았다. 타이핑도 안 되고, JavaScript로 focus()를 강제로 줘도 소용없었다.
디버깅 과정
“input이 없는 건 아니겠지?”
document.querySelectorAll('input')
rc-editable-input 시리즈가 정상적으로 잡혔다. input은 있었다.
“혹시 disabled? pointer-events?”
console.log('disabled:', el.disabled); // false
console.log('pointerEvents:', ...pointerEvents) // auto
console.log('visibility:', ...visibility); // visible
전부 정상. input 자체의 문제가 아니었다.
“그럼 위에 뭔가 덮고 있나?”
const rect = input.getBoundingClientRect();
document.elementFromPoint(rect.left + rect.width/2, rect.top + rect.height/2);
// → sketch-picker div 반환 (input이 아님!)
input 좌표를 찍었는데 input이 아닌 상위 div가 반환됐다. 뭔가가 input 위를 덮고 있었다.
“sketch-picker를 무력화하면?”
document.querySelector('.sketch-picker').style.pointerEvents = 'none';
picker가 닫혀버렸다. backdrop 클릭이 통과된 것이다. 즉, backdrop이 SketchPicker 위에 올라와 있었다.
“근데 focus()는 왜 안 됐지?”
picker에 포커스가 잡히는지 확인하기 위해 Portal 렌더링 위치를 살펴봤다. Portal 대상이 choice-value-dialog — MUI Dialog의 루트 div였다.
원인: 두 가지가 동시에 문제였다
1. Portal이 MUI focus trap 밖에 렌더링되고 있었다
MUI Dialog는 MuiDialog-scrollPaper 내부만 focus trap으로 관리한다. 루트 div(choice-value-dialog)에 Portal로 렌더링하면 focus trap 밖으로 인식되어 MUI가 포커스를 차단한다.
MUI Dialog 루트
├── MuiBackdrop-root
├── MuiDialog-scrollPaper ← focus trap 범위
│ └── dialog 컨텐츠
└── SketchPicker Portal ← ❌ focus trap 밖 → 포커스 차단
2. backdrop이 SketchPicker 위를 덮고 있었다
position: fixed + top/right/bottom/left: 0 backdrop을 SketchPicker와 같은 부모 안에 두면, stacking context 충돌로 backdrop이 picker 위에 올라와 모든 클릭을 가로챈다.
왜 하나만 고쳐서는 안 됐나
| 상황 | 결과 |
|---|---|
| Portal 위치만 수정 | backdrop이 여전히 input을 덮음 → 클릭 불가 |
| backdrop 구조만 수정 | focus trap이 막음 → 포커스 불가 |
| 둘 다 수정 | ✅ 정상 동작 |
해결
Portal을 MuiDialog-scrollPaper 안에 렌더링해서 focus trap 범위 안으로 들어가고, backdrop과 picker를 형제 관계로 분리한 뒤 stopPropagation으로 클릭 전파를 차단했다.
<Portal> {/* MuiDialog-scrollPaper 대상 */}
{/* 전체 화면 backdrop */}
<div style=
onClick={props.onClose}
/>
{/* picker: backdrop보다 위, 클릭 전파 차단 */}
<div style=
onClick={(e) => e.stopPropagation()}
>
<SketchPicker ... />
</div>
</Portal>
배운 것
- MUI Dialog 안에서 Portal 쓸 때는 반드시
MuiDialog-scrollPaper를 대상으로 해야 한다. 루트 div에 붙이면 focus trap 밖이 된다. - backdrop과 picker는 같은 부모 안에 두면 안 된다. stacking context 충돌이 생긴다. 형제로 분리하고 z-index +
stopPropagation으로 명확히 구분해야 한다. focus()도 안 먹히고,pointer-events도 정상인데 클릭이 안 된다면 focus trap을 의심하자.
댓글남기기