# Fullscreen API in installed PWAs

> Enter and leave element fullscreen from an installed PWA, detect state changes, handle rejected requests, and keep an in-app exit control.

The Fullscreen API lets an installed PWA ask to display an element using the available screen area and later leave that mode. It is separate from the web app manifest's display mode: `requestFullscreen()` changes the current document after launch, while the manifest controls how the installed app opens.

## Support

BCD `api.Element.requestFullscreen` records implementations in Chrome, Edge, Firefox, and Safari, with qualifications for some options and older releases. Check the returned promise and the `fullscreenchange` event instead of inferring success from the app being installed ([Element.requestFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen), MDN).

## Syntax

```js
await element.requestFullscreen()
await element.requestFullscreen(options)
await document.exitFullscreen()
```

`requestFullscreen()` asks to make the element fullscreen. `exitFullscreen()` asks to return the document to its previous presentation.

## Parameters

The optional object can contain `navigationUI`, whose values are `"auto"`, `"hide"`, and `"show"`. MDN also documents the experimental `screen` option for selecting a `ScreenDetailed` target.

The request promise resolves with `undefined` after the transition completes. Read `document.fullscreenElement` in a `fullscreenchange` listener to distinguish entry from exit.

## Exceptions

MDN documents a rejected `TypeError` when the document is not fully active, the element is detached, fullscreen is disallowed by Permissions Policy or access controls, the element is the document, or the element is an already-open popover. A request normally also needs transient user activation.

An iframe must be permitted to use fullscreen. For cross-origin content, configure the `fullscreen` Permissions Policy and the iframe's `allow` attribute as described by MDN.

:::caution
The Web Platform Tests source names its no-activation case `Element#requestFullscreen() rejects without user activation by default` and asserts a JavaScript `TypeError`. This exact assertion is reproducible in a WPT runner without depending on vendor-specific console text.
:::

## Examples

These examples keep entry, exit, and presentation changes inside the page so the interface still works when the browser declines a request.

### Detecting support

Test both methods before exposing the fullscreen control. When either method is absent, this branch hides the control and leaves the stage in its inline presentation.

```js
const button = document.querySelector('#fullscreen');
const status = document.querySelector('#status');

if ('requestFullscreen' in Element.prototype && 'exitFullscreen' in Document.prototype) {
  button.hidden = false;
} else {
  button.hidden = true;
  status.textContent = 'Fullscreen is unavailable; content remains inline.';
}
```

BCD records the two methods separately under `api.Element.requestFullscreen` and `api.Document.exitFullscreen` ([Element.requestFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen), MDN; [Document.exitFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Document/exitFullscreen), MDN).

### Toggle a stage from an explicit control

The button click supplies user activation. The unsupported branch keeps the content inline, and the `catch` branch reports a denied request without claiming that fullscreen was entered.

```html
<main id="stage" tabindex="-1">
  <button id="fullscreen" type="button">Enter fullscreen</button>
  <p>Presentation content</p>
  <p id="status" role="status"></p>
</main>

<script type="module">
  const button = document.querySelector('#fullscreen');
  const stage = document.querySelector('#stage');
  const status = document.querySelector('#status');

  if (!stage.requestFullscreen || !document.exitFullscreen) {
    button.hidden = true;
    status.textContent = 'Fullscreen is unavailable; content remains inline.';
  } else {
    button.addEventListener('click', async () => {
      try {
        if (document.fullscreenElement) {
          await document.exitFullscreen();
        } else {
          await stage.requestFullscreen();
        }
      } catch (error) {
        status.textContent = `Fullscreen was not entered: ${error.name}`;
      }
    });

    document.addEventListener('fullscreenchange', () => {
      const active = Boolean(document.fullscreenElement);
      button.textContent = active ? 'Exit fullscreen' : 'Enter fullscreen';
      status.textContent = active ? 'Fullscreen is active.' : 'Fullscreen is closed.';
    });
  }
</script>
```

The button is a descendant of the fullscreen element, so it remains in the fullscreen presentation as an in-document exit control.

### Adjust the stage while it is fullscreen

Use the `:fullscreen` pseudo-class to change only the active fullscreen element. This keeps the normal inline presentation unchanged.

```css
#stage:fullscreen {
  display: grid;
  place-content: center;
  padding: 2rem;
  background: Canvas;
  color: CanvasText;
}
```

The selector stops matching after fullscreen exits, so the stage returns to its regular page styles without a JavaScript cleanup step.

## See also

- [Fullscreen API](https://fullscreen.spec.whatwg.org/) (WHATWG)
- [Element.requestFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen) (MDN)
- [Manifest display modes](/reference/manifest/display/)
- [PWAs on desktop](/reference/platforms/desktop/)
- [Accessibility in standalone PWAs](/guides/accessibility/)