React.js
[React] createPortal을 사용한 z-index 제어
Chunho
2024. 12. 4. 11:09
룰렛을 구현하던 중 React-Tooltip과 디자인이 맞물려 원하는대로 툴팁의 레이어가 위치하지 않게되는 문제가 발생하였다.
우선 룰렛은
Wheel(원판)
outline(원판 외부 테두리)
pointer(룰렛 포인터)
tooltip(원판에 있는 각 아이템을 클릭했을 시 나오는 툴팁) 으로 구성이 되어있다.
- wheel: 1
- outline: 2
- tooltip: 4
- pointer: 3
그리고 각 요소의 z-index는 위와 같이 나타나야 한다. 즉 툴팁은 가장 상단에 위치해야하는 상황이다.
이 때 디자인상 컴포넌트 트리 구조가
wheel 내부에 outline, tooltip이 위치해야 하였고, pointer는 wheel 외부에 독립적으로 존재해야하는 상황이였다.
이 때 문제는 tooltip이 wheel 안에 있었기에, tooltip의 z-index를 높게 지정해주어도 React-tooltip의 특성 상 wheel이 pointer보다 z-index가 낮기에 tooltip이 pointer의 아래쪽에 위치하는 것이였다.
이 문제를 해결하기 위해 react portal을 사용하였다.
react-dom에서 createPortal을 import 해준 뒤
{typeof document !== 'undefined' && (
createPortal(
<Tooltip
id={`item_${item.id}`}
offset={pxToRem(8)}
opacity={1}
place={"top"}
render={() => (
<div className={styles.tooltip}>
<div>
{LanguageService.translate(
item?.rewardInfo?.iconDetails?.[0]
?.nameMultilingualId ?? ""
)}
</div>
<div>
{LanguageService.translate(
item?.rewardInfo?.iconDetails?.[0]
?.tooltipMultilingualId ?? ""
)}
</div>
</div>
)}
style={{
background: COLORS.secondary30,
borderRadius: 4,
zIndex: 99,
}}
arrowColor={COLORS.secondary30}
classNameArrow={styles.arrow}
openEvents={{
click: true,
}}
className={styles.tooltip_wrapper}
clickable={true}
/>,
document.body
) as React.ReactNode
)}
위와 같이 포탈을 통해 tooltip을 body 직접 아래에 렌더링시켜 DOM구조상 완전히 독립적인 위치에 존재하게 하여 문제를 해결할 수 있었다.
(tooltip의 z-index가 의도한대로 동작할 수 있었다.)