- HTML
<dialog> 요소는 브라우저 네이티브 모달·비모달 대화상자를 만들며, 모달은 페이지 나머지 영역을 inert 상태로 만들어 상호작용을 차단함
- 열고 닫는 방식은
showModal(), show(), close()가 기본이며, <form method="dialog">, Invoker Commands API, Popover API로도 선언형 제어가 가능함
closedby 속성은 사용자가 대화상자를 닫을 수 있는 경로를 any, closerequest, none으로 나누고, 열린 방식에 따라 기본 동작이 달라짐
- 접근성에서는 초기 포커스와 명시적 닫기 버튼이 중요하며,
showModal()로 열린 대화상자는 기본적으로 첫 번째 포커스 가능 요소와 Esc 키 닫기를 제공함
- 스타일링은
:modal, :open, ::backdrop을 활용하고, 애니메이션에는 display, overlay, @starting-style, transition-behavior: allow-discrete 같은 이산 전환 처리가 필요함
<dialog>의 역할과 모달 동작
- HTML
<dialog> 요소는 모달 및 비모달 대화상자를 만들기 위한 요소임
- 모달 대화상자는 다른 UI 요소와의 상호작용을 막고, 페이지의 나머지 부분을
inert 상태로 만듦
- 비모달 대화상자는 열린 상태에서도 페이지의 나머지 부분과 계속 상호작용할 수 있음
열림 상태와 닫기 정책
<dialog>는 전역 속성을 포함하지만, tabindex 속성은 사용하면 안 됨
<dialog> 자체는 상호작용 요소가 아니며 포커스를 받지 않음
- 내부 콘텐츠와 닫기 버튼은 포커스를 받고 상호작용할 수 있음
open 속성은 대화상자가 활성 상태이며 상호작용 가능함을 나타냄
open 속성이 없으면 사용자에게 보이지 않음
- 대화상자를 표시할 때는
open 속성보다 .show() 또는 .showModal() 사용이 권장됨
open 속성으로 열린 <dialog>는 비모달임
- 비모달 대화상자의 열림·닫힘 상태를
open 속성 토글로 바꿀 수는 있지만 권장되지 않음
closedby 속성은 사용자가 어떤 방식으로 대화상자를 닫을 수 있는지 지정함
any: 세 가지 방식 모두로 닫을 수 있음
- 대화상자 바깥 클릭 또는 탭 같은 light dismiss
- Esc 키, 모바일의 뒤로 가기 또는 dismiss 제스처 같은 플랫폼별 동작
HTMLDialogElement.close()를 호출하는 버튼이나 <form> 제출 같은 개발자 지정 방식
closerequest: 플랫폼별 동작과 개발자 지정 방식으로 닫을 수 있음
none: 개발자 지정 방식으로만 닫을 수 있음
- 유효한
closedby 값이 없으면 showModal()로 열린 경우 closerequest처럼, 그 외에는 none처럼 동작함
JavaScript와 선언형 제어
- JavaScript로
<dialog> 표시와 닫기를 직접 제어할 수 있음
showModal(): 모달 대화상자 표시
show(): 비모달 대화상자 표시
close(): 대화상자 닫기
<dialog> 안의 <form>을 method="dialog"로 제출해 닫을 수도 있음
- 모달 대화상자는 Esc 키로도 닫을 수 있음
- Invoker Commands API는 버튼 속성만으로 모달 대화상자를 열고 닫을 수 있게 함
<button>에 commandfor와 command 속성을 지정함
- 대화상자에 사용할 수 있는 명령은
"show-modal", "close", "request-close"임
<button command="show-modal" commandfor="my-dialog">Open dialog</button>
<dialog id="my-dialog">
<p>This dialog was opened using an invoker command.</p>
<button commandfor="my-dialog" command="close">Close</button>
</dialog>
- Popover API는 비모달 대화상자를 선언적으로 열고 닫고 토글할 수 있게 함
<dialog>에 popover 속성을 추가해 팝오버로 만듦
- 버튼이나 입력 요소에
popovertarget, popovertargetaction을 지정함
- 팝오버 대화상자는 비모달이므로 바깥을 클릭해 닫을 수 있음
popover 값을 지정하지 않으면 기본값 "auto"가 사용되어 light dismiss가 활성화됨
popover="manual"은 light dismiss를 비활성화하며, 닫기 버튼 같은 별도 방식이 필요함
popovertargetaction을 생략하면 기본값 toggle이 사용됨
폼 제출과 닫기 처리
- 모든
<dialog>에는 닫기 메커니즘이 필요하며, 물리 키보드가 없는 기기에서도 동작해야 함
- 닫기 방식은 여러 가지가 있음
<dialog> 내부 <form>에 method="dialog" 를 설정하고 제출
- light dismiss가 활성화된 상태에서 대화상자 바깥 클릭
- 허용된 대화상자에서 Esc 키 누르기
HTMLDialogElement.close() 호출
<form method="dialog"> 또는 제출 버튼의 formmethod="dialog"는 대화상자를 닫음
- 폼 컨트롤 상태는 저장되지만 제출되지는 않음
returnValue는 활성화된 버튼의 값으로 설정됨
- 필수 입력값이 있는 폼에서는 사용자 에이전트가 값이 제공될 때까지 일반 제출로 대화상자를 닫지 못하게 함
- 닫기 버튼에
formnovalidate 를 사용하면 폼 검증을 우회할 수 있음
- JavaScript에서
dialog.close()를 호출해도 닫을 수 있음
포커스와 접근성
showModal()로 <dialog>를 열면 기본적으로 첫 번째 중첩된 포커스 가능 요소에 포커스가 설정됨
- 특정 대화상자에서 가장 적절한 초기 포커스 위치를 지정하려면
autofocus 속성을 사용할 수 있음
- 즉시 상호작용할 요소가 없으면 닫기 버튼에
autofocus를 두는 것이 권장됨
- 동적으로 렌더링되는 대화상자처럼 초기 포커스 위치가 불확실하면
<dialog> 자체가 적절한 초기 포커스 위치가 될 수 있음
- 모든 사용자가 닫을 수 있도록 확인, 취소, 닫기 버튼 같은 명시적 버튼을 포함하는 방식이 가장 견고함
showModal()로 호출된 대화상자는 기본적으로 Esc 키로 닫힘
- 비모달 대화상자는 기본적으로 Esc 키로 닫히지 않음
- 키보드 사용자는 모달 대화상자가 Esc 키로 닫히기를 기대함
- 여러 모달 대화상자가 열려 있으면 Esc 키는 마지막에 표시된 대화상자만 닫아야 하며,
<dialog> 사용 시 브라우저가 이 동작을 제공함
- 네이티브
<dialog>는 다른 요소로 만든 커스텀 대화상자에서 직접 복제해야 하는 사용성 및 접근성 기능을 제공함
- 브라우저는
<dialog>를 ARIA role="dialog"를 사용하는 커스텀 대화상자와 유사하게 노출함
showModal()로 호출된 <dialog>는 암묵적으로 aria-modal="true"를 가짐
show(), open 속성, 기본 display 변경으로 표시된 <dialog>는 aria-modal="false"로 노출됨
- 모달 대화상자 구현 시
<dialog>와 그 콘텐츠 외의 모든 것은 inert로 렌더링되어야 하며, showModal() 사용 시 브라우저가 이 동작을 제공함
CSS 스타일링과 backdrop
<dialog>는 일반 요소처럼 요소 이름으로 선택할 수 있음
- 상태 기반 스타일링에는
:modal, :open 의사 클래스를 사용할 수 있음
- 모달 대화상자의 배경은
::backdrop 의사 요소로 스타일링할 수 있음
showModal()로 대화상자를 표시할 때 <dialog> 뒤에 나타나는 backdrop에 적용됨
- inert 상태인 뒤쪽 콘텐츠를 흐리게 하거나 어둡게 하거나 가릴 수 있음
예제로 보는 사용 패턴
- Invoker Commands API 예제는
command="show-modal" 버튼으로 대화상자를 열고, command="close" 버튼으로 닫음
- “Open dialog” 버튼으로 열 수 있음
- “Close” 버튼 또는 Esc 키로 닫을 수 있음
- Popover API 예제는
popover, popovertarget, popovertargetaction으로 비모달 대화상자를 열고 닫음
- “Close” 버튼, Esc 키, 대화상자 바깥 선택으로 닫을 수 있음
popover="manual"을 쓰면 light dismiss가 비활성화됨
open 속성 예제는 페이지 로드 시 이미 열린 HTML-only 비모달 대화상자를 만듦
<form method="dialog">의 “OK” 버튼으로 닫을 수 있음
- 닫힌 뒤 다시 여는 방식은 제공되지 않음
- 비모달 대화상자 표시는
HTMLDialogElement.show() 사용이 선호됨
- 모달 대화상자 예제는
.showModal()로 열고 close()로 닫음
::backdrop으로 그라데이션 배경을 스타일링함
- 대화상자가 열리면 대화상자 외부는 inert 상태가 되어 문서와 상호작용할 수 없음
returnValue 예제는 폼과 버튼 값으로 대화상자의 반환값을 다룸
- 기본
returnValue는 빈 문자열이거나, 대화상자 내부 폼을 제출한 버튼의 값임
- “Confirm” 버튼은 선택값을
close()에 넘겨 반환값으로 사용함
- Esc 키로 닫으면
returnValue가 갱신되지 않고 close 이벤트도 발생하지 않아 <output> 텍스트가 업데이트되지 않음
<dialog> 애니메이션
- 숨겨진
<dialog>는 display: none, 표시된 <dialog>는 display: block이 됨
- 표시 상태가 바뀔 때 top layer와 접근성 트리에 추가되거나 제거됨
<dialog>를 애니메이션하려면 display 속성이 애니메이션 가능해야 함
- 지원 브라우저는
display를 이산 애니메이션 방식으로 처리함
none에서 block으로 바뀔 때는 0% 시점에 block으로 전환되어 전체 애니메이션 동안 보임
block에서 none으로 바뀔 때는 100% 시점에 none으로 전환되어 전체 애니메이션 동안 보임
-
CSS transition으로 애니메이션
- CSS transition으로
<dialog>를 애니메이션하려면 다음 기능이 필요함
@starting-style: 대화상자가 열릴 때마다 전환 시작값 제공
display 전환: 전환 동안 대화상자를 보이는 display 값으로 유지
overlay 전환: top layer 제거를 전환 완료까지 지연
transition-behavior: allow-discrete: 기본적으로 애니메이션되지 않는 display, overlay의 이산 전환 활성화
:open 의사 클래스를 지원하지 않는 브라우저에서는 dialog[open] 속성 선택자로 열린 상태를 스타일링할 수 있음
<dialog>는 표시될 때마다 display: none에서 display: block으로 바뀌므로, 진입 전환마다 @starting-style에서 dialog:open 스타일로 전환됨
-
keyframe 애니메이션
- CSS keyframe 애니메이션은 transition과 다른 제약을 가짐
@starting-style을 제공하지 않음
display 값을 keyframe 안에 포함함
allow-discrete를 명시적으로 활성화할 필요가 없음
overlay를 keyframe에 설정할 필요도 없음
- backdrop fade-out은 대화상자가 닫힐 때 backdrop이 DOM에서 즉시 제거되어 애니메이션할 수 없음
기술 요약
- 콘텐츠 카테고리: flow content, sectioning root
- 허용 콘텐츠: flow content
- 시작 태그와 종료 태그는 모두 필수이며 태그 생략은 없음
- 허용 부모: flow content를 받는 모든 요소
- 암묵적 ARIA 역할:
dialog
- 허용 ARIA 역할:
alertdialog
- DOM 인터페이스:
HTMLDialogElement
- 명세: HTML # the-dialog-element