Popover API로 팝오버 구현하기
(developer.mozilla.org)- 브라우저 기본 기능만으로 페이지 위에 뜨는 팝오버 UI를 만들 수 있어, 메뉴·제안·알림 같은 패턴을 더 일관되게 구현할 수 있음
- Popover API의 팝오버는 항상 비모달이므로, 페이지 상호작용을 막아야 하는 UI에는
<dialog>가 더 적합함 - 간단한 토글은
popover,popovertarget,popovertargetaction같은 HTML 속성으로 처리하고, 필요하면 JavaScript 메서드로 표시 상태를 제어함 ::backdrop,:popover-open,beforetoggle,toggle등으로 스타일과 상태 변화를 다룰 수 있으며, interest invokers는 hover/focus 표시를 JavaScript 없이 지원함- 2025년 1월부터 최신 기기와 브라우저에서 동작하는 Baseline 2025 기능이지만, 오래된 환경이나 일부 세부 기능의 호환성은 확인이 필요함
Popover API가 해결하는 문제
- Popover API는 다른 페이지 콘텐츠 위에 팝오버 콘텐츠를 표시하는 표준 메커니즘을 제공함
- 팝오버는 HTML 속성만으로 제어할 수도 있고, JavaScript API로 표시·숨김 상태를 직접 다룰 수도 있음
- 웹에서 overlays, popups, popovers, dialogs 등으로 불리던 UI 패턴을 브라우저 기본 기능으로 더 일관되게 구현할 수 있음
모달이 필요하면 <dialog>를 사용
- 팝오버 UI는 크게 모달과 비모달로 나뉨
- 모달은 팝오버가 표시되는 동안 나머지 페이지와 상호작용할 수 없음
- 비모달은 팝오버가 떠 있어도 나머지 페이지와 계속 상호작용할 수 있음
- Popover API로 만든 팝오버는 항상 비모달임
- 페이지 상호작용을 막는 모달 팝오버가 필요하면
<dialog>요소가 적합함 <dialog popover>처럼<dialog>에popover를 적용하는 방식도 유효하며, 팝오버 제어와 dialog 의미론을 함께 사용할 수 있음
기본 사용 방식
- Popover API는 사용자 상호작용이 필요한 UI에 자주 쓰일 수 있음
- 액션 메뉴
- 커스텀 toast 알림
- 폼 요소 제안
- 콘텐츠 선택기
- 교육용 UI
- HTML만으로 간단한 팝오버 토글 버튼을 만들 수 있음
<button popovertarget="mypopover">Toggle the popover</button>
<div id="mypopover" popover>Popover content</div>
- JavaScript에서는
HTMLElement.togglePopover()로 팝오버의 표시/숨김 상태를 전환함 - API는 팝오버 상태 변화에 반응하는 이벤트와 스타일링을 돕는 CSS 기능도 함께 제공함
HTML 속성
interestfor- HTML
<a>,<button>,<area>요소나 SVG<a>요소를 interest invoker로 정의함 - 값은 대상 요소의
id이며, invoker 요소에서 interest가 표시되거나 사라질 때 대상 요소가 영향을 받음
- HTML
popover- 요소를 팝오버 요소로 바꾸는 전역 속성임
- 값으로
"auto","hint","manual"상태를 받을 수 있음
popovertarget<button>또는<input>요소를 팝오버 제어 버튼으로 만듦- 값은 제어할 팝오버 요소의 ID임
popovertargetaction- 제어 버튼이 팝오버에 수행할 동작을 지정함
- 가능한 값은
"hide","show","toggle"임
CSS로 다루는 표시 상태
::backdrop- 팝오버 요소 바로 뒤에 놓이는 전체 화면 의사 요소임
- 필요하면 팝오버 뒤의 페이지 콘텐츠에 흐림 같은 효과를 줄 수 있음
interest-delay,interest-delay-start,interest-delay-end- 사용자가 interest를 표시하거나 잃은 시점과 브라우저가 반응하는 시점 사이에 지연 시간을 추가함
:interest-source,:interest-target- interest가 표시된 상태에서 invoker와 연결된 대상 요소에 각각 스타일을 적용할 수 있음
:popover-open- 팝오버 요소가 표시 중일 때만 매칭되는 의사 클래스임
- 열린 상태의 팝오버를 스타일링하는 데 사용함
JavaScript 인터페이스와 DOM 확장
InterestEventinterest와loseinterest이벤트의 이벤트 객체임- 연결된 interest invoker 요소 참조를 담는
source속성을 포함함
ToggleEvent- 팝오버 요소가 표시 상태와 숨김 상태 사이에서 전환될 때 발생하는 이벤트를 표현함
beforetoggle과toggle이벤트의 이벤트 객체임
interestForElement- interest invoker가 대상으로 삼는 요소의 참조를 가져오거나 설정함
HTMLButtonElement,HTMLAnchorElement,HTMLAreaElement,SVGAElement에서 사용할 수 있음
HTMLElement.popover- JavaScript로 요소의 팝오버 상태를 가져오거나 설정함
"auto","hint","manual"값을 사용하며 기능 감지에도 활용됨- HTML 전역 속성
popover값을 반영함
popoverTargetElementHTMLButtonElement와HTMLInputElement에서 제어 버튼이 제어하는 팝오버 요소를 가져오거나 설정함- HTML
popovertarget속성의 JavaScript 대응 기능임
popoverTargetActionHTMLButtonElement와HTMLInputElement에서 수행할 팝오버 동작을 가져오거나 설정함"hide","show","toggle"값을 사용하며popovertargetaction속성을 반영함
메서드와 이벤트
HTMLElement.hidePopover()- 팝오버 요소를 top layer에서 제거하고
display: none으로 스타일링해 숨김
- 팝오버 요소를 top layer에서 제거하고
HTMLElement.showPopover()- 팝오버 요소를 top layer에 추가해 표시함
HTMLElement.togglePopover()- 팝오버 요소를 표시 상태와 숨김 상태 사이에서 전환함
beforetoggle- 팝오버 요소의 상태가 표시와 숨김 사이에서 바뀌기 직전에 발생함
- 팝오버 열림을 막거나, 팝오버 상태에 따라 다른 요소를 업데이트하는 데 사용할 수 있음
toggle- 팝오버 요소의 상태가 바뀐 직후 발생함
interest- interest invoker의 대상 요소에서 interest가 표시될 때 발생함
loseinterest- interest invoker의 대상 요소에서 interest가 사라질 때 발생함
예제와 명세 링크
- Popover API examples: Popover API 예제 모음
- interest invoker examples: interest invoker 예제 모음
- 관련 명세는 HTML 명세의 popover,
beforetoggle,toggle항목에 포함됨
댓글과 토론
Hacker News 의견들
-
Popover API는 CSS 앵커 위치 지정(CSS Anchor Positioning) 까지 들어오면 정말 큰 변화를 만들 것 같음
앵커 위치 지정은 페이지의 다른 요소를 기준으로 요소를 배치하게 해줌
Popover API와 합치면 커스텀 툴팁이나 컨텍스트 메뉴를 선언적으로 구현할 수 있고, PopperJS 같은 라이브러리도 필요 없어짐
https://developer.chrome.com/blog/tether-elements-to-each-ot...
https://popper.js.org/docs/v2/- CSS 앵커 API 사용법을 다룬 새 글을 막 올렸고, 다음 주 Chromium에 들어갈 예정임
https://developer.chrome.com/blog/anchor-positioning-api - 브라우저 지원 현황은 여기서 볼 수 있음
https://caniuse.com/css-anchor-positioning - 지난 몇 년 동안 CSS 앵커 위치 지정이 있었다면 아꼈을 시간이 엄청났을 듯함
- 이게 빠진 핵심 조각임
지난주 새 Popover API로 뭔가 만들어 배포해보려 했는데, 모든 브라우저에서 위치 지정 지원이 부족해서 활용 사례가 크게 제한됐음
마지막 브라우저인 Firefox도 이미 베타에서 앵커 위치 지정을 넣은 것 같으니 오래 걸리진 않을 듯함 - 2024년인데 HTML/CSS에
title같은 툴팁 속성이 없다는 게 놀라움
- CSS 앵커 API 사용법을 다룬 새 글을 막 올렸고, 다음 주 Chromium에 들어갈 예정임
-
모달 대화상자가 필요하면
<dialog>요소도 있음
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...- 펼치기/접기 콘텐츠가 필요하거나, 약간 억지로 쓰면 “드롭다운”에도
<details>를 쓸 수 있음
이상하게도<dialog>나<details>와 달리<popover>는 속성만으로 선언적으로open상태를 만들 수 없는 듯함
빠진 기능처럼 느껴지고, 이 결정에 근거가 있었기를 바람
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/de... - 애니메이션과 일반적인 모달 동작을 요즘 기대 수준까지 맞추려면 꽤 작업이 필요하다고 경고하고 싶음
충분히 가능하긴 하지만 결코 사소한 작업은 아님 - 지적된 것처럼 애니메이션은 더 어렵지만, 접근성을 갖추고 있고 Esc 키로 닫기, 내장 배경, 내장 포커스 트랩을 지원함
Safari 지원까지는 시간이 걸렸지만 이제는 어디서나 쓸 수 있음
태그를 직접 조합하는 것보다 낫다고 봄 - 글 첫 몇 단락에서 이미 다루고 있음
- 펼치기/접기 콘텐츠가 필요하거나, 약간 억지로 쓰면 “드롭다운”에도
-
호스트 운영체제의 창 시스템과 함께 구현된다면 이 기능은 분명 필요해 보임
현재 팝오버는 항상 잘 동작하지 않는 방식으로 흉내 내야 하기 때문임
예를 들어 브라우저 네이티브<select>는 브라우저 창 경계를 넘어 확장될 수 있어서 창에 잘리는 걱정을 안 해도 되지만, Quasar 같은 툴킷의 화려한 가짜 select는 그렇게 못 해서 배치 선택지가 제한됨
제대로 하려면 win32에서는 각 팝오버가 자체 네이티브HWND를 가져야 하고, Cocoa/macOS에서는 자체NSView안에 있어야 할 듯함
지금 브라우저들이 실제로 이렇게 구현하는지, 아니면 그냥 브라우저 창 안에서 덧그리는 방식인지 궁금함- 이 팝오버들은 그냥 일반 DOM 노드이고 일반 CSS로 스타일링됨
웹사이트가 지정된 뷰포트 밖에 그릴 수 있게 허용하면,alert(),confirm(),[title]같은 극히 제한된 경우를 빼고는 브라우저나 운영체제 대화상자를 그럴듯하게 흉내 내기 훨씬 쉬워짐
예를 들면 페이지가 비밀번호 관리자 확장 프로그램의 잠금 해제 위젯을 흉내 낼 수 있음
이건 큰 보안 위험이고, 제한적인 이득에 비해 가치가 없다고 봄
이건 이론적 우려가 아님
사기꾼들은 수년간 브라우저 크롬까지 포함한 가짜 팝업 창 등 매우 그럴듯한 가짜 UI를 만들어왔고, 드래그까지 가능했음
뷰포트 경계 밖으로 그릴 수 없다는 점은 그들이 우회하지 못한 거의 유일한 제한이었음 - 그런 기능이 현실적으로 얼마나 유용할지 모르겠음
작은 기기에서는 웹브라우저가 거의 항상 전체 화면을 덮고, 큰 모니터에서도 보통 최소 한쪽 모서리에 닿아 있음 - 의미적으로도 감지하기 쉬워질 것 같음
접근성과 크롤링 가능성도 그렇고, 누군가 “팝업 금지” 플러그인을 만들고 싶을 때도 유용함 - Firefox는 기술적으로 페이지 콘텐츠 일부를 별도 운영체제 수준 창으로 “튀어나오게” 하는 기능을 지원함
이 기능은 브라우저 메인 프로세스에서 렌더링되는 권한 있는 [X]HTML에서만 쓸 수 있는 XUL 요소를 통해 노출됨
어떤 브라우저 개발자도 일반 웹페이지에 테두리 없는 운영체제 창을 만들 권한을 주고 싶어 하진 않을 것 같음 - 웹 앱이 상상한 것 같은 네이티브 창 시스템 통합을 곧 얻을 것 같지는 않음
일부 표준 컨트롤이 그렇게 동작하는 건 운영체제 네이티브로 구현됐기 때문에 생기는 OS별 구현 부작용이고, 반드시 그렇게 구현해야 하는 것도 아님
- 이 팝오버들은 그냥 일반 DOM 노드이고 일반 CSS로 스타일링됨
-
브라우저에는 내장 팝업 차단기가 있는데 이런 API를 만든다는 게 좀 웃기긴 함
차이가 있다는 건 알지만 그래도 그렇다
90년대 후반과 2000년대 초반의 팝업/팝언더 전쟁을 기억할 만큼 나이가 들었음
그 전투는 이긴 것 같지만, 우리의 주의를 둘러싼 전쟁은 아직 한참 남아 있음- 서로 다른 것을 비교하는 것 같음
팝오버는 필요할 때 맥락 정보를 보여주는 떠 있는 요소임
언급한 것은 완전히 다른 것임 - 말하려는 요지는 알겠지만, 실제로는 비교 대상이 아닌 것 같음
팝업은 운영체제에 쓰레기 창을 뿌려서 최악의 경우 컴퓨터 사용 자체를 방해함
팝오버 대화상자는 탭을 닫으면 끝임
이런 스타일의 팝오버는 정보를 보여주는 데 꽤 유용해서 이미 오래전부터 써왔음
짜증 나게 쓰일 수는 있지만, 모달처럼 진짜 활용 사례도 많음 - 이런 반응이 많이 보이지만 조금 말이 안 됨
지금도 기존div등으로 팝오버를 구현할 수 있음
예: https://getbootstrap.com/docs/5.3/components/popovers/
달라지는 건 마법 같은 추가 라이브러리 없이 팝오버를 구현할 수 있다는 점임
명시적인 “popover” 요소를 막아봤자 사람들은 커스텀 라이브러리를 계속 쓸 뿐임 - 이건 팝업이 아님
사람들이 팝업을 싫어하는 건 침입적이고 별도 창을 갖기 때문임
이 API는div모달을 대체해서 개발자의 시간과 코드를 줄여줌 - 원래 팝업 구현은 애플리케이션 콘텐츠와 운영체제의 경계를 깨고, 팝업 차단기는 그걸 막으려는 것임
이 API는 그 경계를 깨지 않음
그 경계가 깨지면 시스템의 사용성과 안전성이 떨어지므로 원하지 않는 방향임
- 서로 다른 것을 비교하는 것 같음
-
“Popover API로 만든 팝오버는 항상 비모달이다. 모달 팝오버를 만들고 싶다면
<dialog>요소가 맞다”라는데, 왜 그런지 모르겠음
이건 팝오버의 정당한 활용 사례임
특히 열렸을 때 배경을 흐리게 처리한다면 더 그렇고, 흐려진 버튼을 사용자의 클릭이 실수로 누르게 할 수 있다면 그 기능을 왜 제공하는지 의문임
찾아보니 둘을 조합할 수 있음
“팝오버 제어와 대화상자 의미를 결합하고 싶다면<dialog>요소를 팝오버로 만들 수 있다”는 식임
그렇다면 여기서는modal같은 속성이 더 말이 되지 않나 싶음
활용 사례를 분명히 인정하고 있으니까- 아마도 여러 이유 중 하나는
<dialog>가 훨씬 먼저 존재했기 때문일 듯함
- 아마도 여러 이유 중 하나는
-
아주 좋음
제대로 이해했다면 새 기능을 도입한다기보다는, 모달div, 마스크div, 컨테이너div, 불편한 위치 지정 CSS가 필요하던 부분을 단순화하는 것 같음
스타일링을 쉽게 하는 의사 클래스도 추가되고, 마음에 듦- 기본 기능을 JavaScript 없이 쓸 수 있게 해주기도 함
숨겨진 체크박스를 억지로 쓰지 않아도 됨
스타일링과 애니메이션이 들어간 팝오버까지 JS 없이 얼마나 갈지는 모르겠지만, 포커스 처리가 제대로 되는 무JS 지원은 좋음
접근성 지원도 내장됐다고 말하고 싶은데 지금 명세에서는 못 찾겠음
스크린 리더 같은 접근성 도구에 요소를 알리는 것까지 처리한다면 큰 도움이 될 것임
수동으로 하다 보면 꽤 쉽게 빼먹기 때문임 - 이 API는 JavaScript 없이도 DOM에서 팝오버 요소의 표시 상태를 제어할 수 있게 함
확실히 유용함
- 기본 기능을 JavaScript 없이 쓸 수 있게 해주기도 함
-
데모: https://mdn.github.io/dom-examples/popover-api
- 중첩 팝오버 데모에서는 Pizza에서 Ham으로 대각선 이동이 안 됨
Chrome이나 Firefox에서 하위 메뉴가 사라지기 전 지연 시간을 구현한 사람이 아무도 없기 때문임
수십 년의 사용자 경험 연구가 사라졌고, 거의 예상한 대로임
https://mdn.github.io/dom-examples/popover-api/nested-popove... - 브라우저 지원 표에 따르면 된다고 되어 있지만, iOS Safari에서는 동작하지 않는 것 같음
- 중첩 팝오버 데모에서는 Pizza에서 Ham으로 대각선 이동이 안 됨
-
멋져 보이지만, 이 페이지에는 왜 팝오버가 뭔지 보여주는 이미지가 하나도 없는지 모르겠음
- 예제 링크가 있고 여기서 볼 수 있음
https://mdn.github.io/dom-examples/popover-api/ - 이미지가 있으면 유용할 것 같음
대화형 예제로 연결하긴 하는데, 팝오버의 기본 스타일은 그다지 흥미롭지 않아 보임
https://mdn.github.io/dom-examples/popover-api/
- 예제 링크가 있고 여기서 볼 수 있음
-
훌륭함
Popper를 사용해 Stimulus로 만든 커스텀 구현은 여기 있음
https://github.com/tramlinehq/tramline/blob/main/app/javascr...
그리고 대화상자용 구현은 여기 있음
https://github.com/tramlinehq/tramline/blob/main/app/javascr...