트러블슈팅

[Bootstrap 5/Vue.js] 중첩모달

AVONADO 2025. 12. 23. 16:24

 

 

 

 

부트스트랩 잘쓰진않는데... 회사에서 전에 진행한 프로젝트가 부트스트랩 템플릿으로 만든 사이트라 어쩔수없이 ㅠㅠ 쓰게 됐다.

 

모달 위에 모달을 하나 더 띄워야 하는 상황이 생겼는데 부트스트랩은 중첩 모달이 안 된다는..사실이..?

사용자 UI/UX경험 해친다는데 허허;;~~

 

하 그래서 똥꼬쇼 하다가

결국 커스텀 모달을 만들었더요.

 

근데? bs모달 위에 중첩된 모달에 있는 input에 마우스 클릭해도 포커스도 안 가고, 입력도 안 되는 거임!!

 

여기서 진짜 ㅁㅊ고 팔짝! 뛰고싶었음

 

지피티 5.2와 클로드 Sonnet 4.5 를 번갈아가며 써봤지만... 얘네는 도움이 하나도 안 됐다. 내가 프롬프트를 잘못넣은 탓인가 했지만

큰맘먹고 사용량 ㄹㅈㄷ인 클로드 Opus 4.5로 한번 물어봤더니 바로? 해결 됨!!

 

Opus 4.5은 세 가지 방법을 알려줬는데

 

방법 1: 첫 번째 모달 생성 시 옵션 추가

const modal = new bootstrap.Modal(document.getElementById('modalA'), {
  focus: false  // 포커스 강제 설정 비활성화
})

 

인데? 첫번째 모달 버튼으로 visible 처리하고있고 저거 뭔소린지 모르겠는데 한번더물어보면 사용량 깎여서 아까우니까 안 물어봄 그래서 안 함

 

방법 2: 커스텀 모달이 열릴 때 동적으로 처리

watch(
  () => visible.value,
  async (isVisible) => {
    const firstModal = document.getElementById('modalA')
    
    if (isVisible) {
      // Bootstrap 모달의 focusin 이벤트 차단
      const handleFocusin = (e: FocusEvent) => {
        e.stopImmediatePropagation()
      }
      document.addEventListener('focusin', handleFocusin)
      
      // 나중에 제거할 수 있도록 저장
      ;(window as any).__customModalFocusHandler = handleFocusin

      if (firstModal) {
        firstModal.style.pointerEvents = 'none'
      }

      await nextTick()
      setTimeout(() => {
        passwordInput.value?.focus()
      }, 150)
    } else {
      // focusin 핸들러 제거
      const handler = (window as any).__customModalFocusHandler
      if (handler) {
        document.removeEventListener('focusin', handler)
      }
      
      if (firstModal) {
        firstModal.style.pointerEvents = 'auto'
      }
      password.value = ''
      isLoading.value = false
    }
  },
  { immediate: true }
)

 

커스텀 모달의 watch를 저대로 수정했는데 이건 실패. 안 됐음

 

방법 3 (가장 간단): CSS로 해결

<input class="form-control"
  ref="passwordInput
  @mousedown.stop
  @focus.stop
  v-model="password"/>
<div v-if="visible" tabindex="-1" 
  @focusin.stop
  @mousedown.stop
  style="position: fixed; top:20%; left:50%; transform: translateX(-50%);z-index: 1060;">

 

요거 추가했더니 됐다!!

 

거의 오후 전부를 중첩모달에 할애해버렸지만... 다음부턴 시간을 아낄 수 있겠다ㅎㅎ

 

 

아니? 다음부턴 팀장님께 부트스트랩 쓰지 말자고 제안한다.

 

 

 

  • 부트스트랩 중첩모달 띄울 시 인풋 입력 안 되는 이유!!
    • 클로드님 가라사대 bs모달이 focusin 이벤트 버블링을 감지해서 포커스를 가로채는데, .stop 수식어로 이벤트 전파 자체를 막아서 해결 된 것이다.
    • 참고로 나중에 다른 input이나 요소 추가할 때도 같은 문제가 생기면, 커스텀 모달 컨테이너에 한 번만 걸어두면 된다고 합니다~
<div v-if="visible" 
  @focusin.stop
  @mousedown.stop
  tabindex="-1" 
  style="position: fixed; top:20%; left:50%; transform: translateX(-50%); z-index: 1060;">
  <!-- 내부 요소들은 개별 처리 필요 없음 -->
</div>

 

 

 

+)

정답을 못맞춘 지피티를 정신교육시켰어요!

 

 

왜냐면 클로드는 회사에서 결제해준 계정이고

지피티는 제 개인 계정이라

더 친하게 지내야할건 지피티여서!!

집에서 혼자 개발할 때의 개발속도 증진을 위해!!!!!!!!!!!!