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가 의도한대로 동작할 수 있었다.)