๐Ÿ–ฅ๏ธ Chapter 54: The Fullscreen API

Exiting Fullscreen & State Recovery

Master `document.exitFullscreen()`, the Escape key security interceptor, nested fullscreen stack unwinding, and layout state recovery.

LEARNING OBJECTIVES โŒต
  • Understand why exitFullscreen() is invoked on the Document object rather than individual elements.
  • Handle Promise resolution and capture TypeError exceptions when exiting fullscreen.
  • Explain how browsers handle the user's Escape key and why e.preventDefault() cannot trap or block it.
  • Unwind multi-level nested fullscreen element stacks cleanly.
  • Restore component layout states, scroll positions, and canvas aspect ratios upon exiting.
๐ŸŽฌ INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
๐ŸŒ
1. Input
Directives & Tags
โš™๏ธ
2. Parse
Tokenizer & AST
๐ŸŒณ
3. Layout
Box Model & Flow
๐ŸŽจ
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

๐Ÿ“– The Mental Model & Story (Intuitive Foundation)

Imagine stepping into a high-security submarine airlock chamber. To enter the chamber (diving into fullscreen), you activate the hatch mechanism on a specific submarine compartment (compartment.requestFullscreen()).

However, once you are inside the submerged airlock, there isn't a separate hatch control for every single wall or gadget. The central command station controls the overall atmosphere and pressure of the vessel (document.exitFullscreen()). Furthermore, the airlock has a bright red manual emergency override lever (Escape key) that immediately vents the water and reopens the chamber doorโ€”no software or electronic lock can ever override that mechanical safety lever.

THE FULLSCREEN CONTROL ASYMMETRY
+-------------------------------------------------------------------------------+
| ENTRY (Specific Element Level)                                                |
|                                                                               |
|   myVideoElement.requestFullscreen()     <-- Called on specific DOM ELEMENT   |
|   myCanvasElement.requestFullscreen()    <-- Promotes that targeted element   |
+-------------------------------------------------------------------------------+
                                       |
                                       v
+-------------------------------------------------------------------------------+
| EXIT (Document Master Level)                                                  |
|                                                                               |
|   document.exitFullscreen()             <-- Called on DOCUMENT object        |
|   [ESC Key Pressed by User]             <-- Browser OS-Level Master Override |
+-------------------------------------------------------------------------------+

This asymmetry is one of the most common stumbling blocks for web developers: You request fullscreen on an Element, but you exit fullscreen from the Document.


Technical Deep Dive & Specifications

The document.exitFullscreen() Method Signature

document.exitFullscreen(): Promise<void>

Under the WHATWG specification:

  • exitFullscreen() is defined on the DocumentOrShadowRoot interface.
  • It returns a Promise that resolves with undefined once the browser has vacated the Top Layer and resized the viewport back to standard windowed mode.
  • If the document is not currently in fullscreen mode (i.e., document.fullscreenElement === null), invoking document.exitFullscreen() immediately rejects the Promise with a TypeError.
// โŒ WRONG: Attempting to call exit on an element
myElement.exitFullscreen(); // Uncaught TypeError: myElement.exitFullscreen is not a function

// โŒ RISKY: Calling exit when no element is fullscreen
await document.exitFullscreen(); // Rejects if already in normal window mode!

// โœ… SAFE PATTERN: Check document.fullscreenElement first
async function toggleFullscreen(targetElement) {
  if (!document.fullscreenElement) {
    await targetElement.requestFullscreen();
  } else {
    await document.exitFullscreen();
  }
}

The Browser Escape Key Interceptor

To prevent malicious websites from trapping users in full-screen phishing environments, browser engines implement a hardcoded, non-suppressible Escape Key Interceptor:

[User Presses ESC Key]
          |
          v (Hardware / OS Level)
[Browser Engine Intercepts ESC]
          |
          +---> 1. Instantly triggers exitFullscreen() workflow
          |
          +---> 2. Dispatches 'keydown' / 'keyup' event to DOM
                   (Note: e.preventDefault() is IGNORED by the browser)
          |
          v
[Top Layer Collapsed & 'fullscreenchange' Dispatched]

[!WARNING] Escape Cannot Be Blocked: Calling event.preventDefault() or event.stopPropagation() inside a keydown listener for the Escape key will not prevent the browser from exiting fullscreen mode. This is a fundamental web security invariant.


Nested Fullscreen Element Stacks

Modern browsers support nested fullscreen transitions. If an element Container A is currently in fullscreen mode, and a child element Video B calls requestFullscreen(), the browser pushes Video B to the top of the fullscreen stack.

INITIAL ENTRY:
[ Top Layer Stack: Container A ] -> document.fullscreenElement === Container A

NESTED ENTRY:
[ Top Layer Stack: Video B (Active), Container A (Previous) ] -> document.fullscreenElement === Video B

FIRST document.exitFullscreen():
[ Top Layer Stack: Container A (Active) ] -> document.fullscreenElement === Container A

SECOND document.exitFullscreen():
[ Top Layer Stack: EMPTY ] -> document.fullscreenElement === null

When document.exitFullscreen() is called:

  1. The browser removes the topmost element (Video B).
  2. If another element was previously fullscreen (Container A), it becomes the active document.fullscreenElement.
  3. Only when the stack is completely empty does the document return to normal windowed mode.

๐Ÿ’ป Interactive Code Playground

Starter Code

Line-by-Line Code Breakdown

  • Line 132โ€“136 (incrementBtn): Modifies in-memory state (count). This proves that entering or exiting the Top Layer does not reload the page or reset JavaScript runtime state.
  • Line 139โ€“151 (toggleBtn): Implements the canonical idempotent toggle pattern: checking document.fullscreenElement to decide whether to call element.requestFullscreen() or document.exitFullscreen().
  • Line 154โ€“163 (exitBtn): Demonstrates safe invocation of document.exitFullscreen() guarded by a document.fullscreenElement existence check.
  • Line 166โ€“181 (document.addEventListener('fullscreenchange')): Listens to the browser's global lifecycle event. Crucially, this event fires regardless of whether the user clicked our custom exit button or pressed the physical keyboard Escape key!

Expected Browser Render Output

  1. The user clicks "Increment Ticker" several times (counter reads 5).
  2. The user clicks "Toggle Fullscreen". The dashboard fills the entire monitor, and the button label switches to "Exit Fullscreen".
  3. The user hits the physical Escape key on their keyboard. The dashboard immediately shrinks back to normal layout.
  4. The counter still displays 5โ€”proving 100% DOM and JavaScript memory state retention.

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45ยฐC
INSPECTING DOM: VALID
TAGS: SCANNING...

๐Ÿ‹๏ธ Hands-On Exercise

๐ŸŽฏ The Challenge: Construct a Multi-Level Fullscreen Dashboard with Graceful Exit

Instructions:

  1. Create a parent container (#presentationDeck) containing two nested child slides (#slideA and #slideB).
  2. Provide a button to promote #presentationDeck to fullscreen.
  3. Inside Slide A, provide a second button that promotes #slideA into nested fullscreen mode.
  4. Implement an Exit Controller that displays how many levels are in the fullscreen stack and exits one level at a time.
  5. Record every exit action in a real-time event log.

๐Ÿ Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45ยฐC
INSPECTING DOM: VALID
TAGS: SCANNING...

โš ๏ธ Common Pitfalls

  1. Calling element.exitFullscreen(): There is no exitFullscreen() method on DOM elements. It exists exclusively on the document object.
  2. Uncaught Rejections on Duplicate Exit: Calling document.exitFullscreen() when no element is currently fullscreen causes a Promise rejection. Always check if (document.fullscreenElement) prior to calling.
  3. Attempting to Trap the User: Trying to re-enter fullscreen immediately inside an Escape key event listener will be blocked by the browser because the Escape key is not classified as an activation gesture.

๐Ÿ’ก Pro Tips

  1. Idempotent Fullscreen Helper: Write a lightweight helper utility:
    export const toggleFullscreen = async (el = document.documentElement) => {
      if (document.fullscreenElement) {
        await document.exitFullscreen();
      } else {
        await el.requestFullscreen();
      }
    };
    
  2. Track Scroll Restoration: When exiting fullscreen on a complex document, verify that window.scrollTo() is not unintentionally shifted by layout resizing. Conforming browsers preserve scroll offsets automatically.

๐Ÿ“Œ Key Takeaways

  • document.exitFullscreen() exits fullscreen mode and returns a Promise.
  • Fullscreen requests are initiated on individual Elements, but exit calls are executed globally on the Document.
  • The physical keyboard Escape key is hardwired to exit fullscreen mode and cannot be intercepted or suppressed by application JavaScript.
  • Browsers maintain an internal fullscreen element stack, allowing nested components to unwind layer by layer.
  • DOM state, event listeners, input values, and media playback remain completely uninterrupted when exiting fullscreen.
  • --
โญ LEARN: HTML ๐ŸŒŸ โš”๏ธ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

Why does calling myVideo.exitFullscreen() throw a TypeError in JavaScript?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

What happens if a developer attempts to call e.preventDefault() inside a keydown handler for the Escape key while in fullscreen?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

If Element B is requested fullscreen while Element A is already fullscreen, what happens on the first call to document.exitFullscreen()?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP