# Screen Orientation API (lock and unlock)

> Read screen orientation changes, request and release an orientation lock, handle rejected requests, and provide a responsive fallback.

The Screen Orientation API exposes the document's orientation through `screen.orientation`. It reports the current type and angle, fires a `change` event, and provides `lock()` and `unlock()` for requesting and releasing an orientation lock ([Screen Orientation](https://w3c.github.io/screen-orientation/), W3C).

## Where it is supported

MDN marks the `ScreenOrientation` interface as widely available but marks `lock()` as limited availability. MDN also notes that orientation locking is typically enabled on mobile devices when the browser context is fullscreen, while the specification permits user agents to require fullscreen or an installed web application before locking ([ScreenOrientation: lock() method](https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/lock), MDN; [Screen Orientation](https://w3c.github.io/screen-orientation/#dom-screenorientation-lock), W3C).

## Syntax

```js
screen.orientation.type
screen.orientation.angle
screen.orientation.addEventListener("change", listener)

await screen.orientation.lock(orientation)
screen.orientation.unlock()
```

`lock()` returns a promise that resolves with `undefined` after the lock is applied. `unlock()` returns `undefined`; the specification explains that a user agent might not know whether returning to the default orientation will change the screen ([Screen Orientation](https://w3c.github.io/screen-orientation/#dom-screenorientation-unlock), W3C).

## Members

`screen.orientation` is a `ScreenOrientation` object with these members, as defined by the specification.

| Member | Type | Description |
|---|---|---|
| `type` | `OrientationType` (read-only) | The current value: `portrait-primary`, `portrait-secondary`, `landscape-primary`, or `landscape-secondary`. |
| `angle` | `unsigned short` (read-only) | The counter-clockwise rotation from the screen's natural orientation, in degrees. |
| `lock(orientation)` | `Promise<undefined>` | Requests a lock to an `OrientationLockType` value. |
| `unlock()` | `undefined` | Releases the active lock and returns to the default orientation. |
| `onchange` | `EventHandler` | Handles the `change` event fired when the reported orientation type or angle changes. |

The `orientation` argument accepts `any`, `natural`, `landscape`, `portrait`, `portrait-primary`, `portrait-secondary`, `landscape-primary`, or `landscape-secondary`. The specification allows a user agent or platform to support only a subset of those lock values ([OrientationLockType enum](https://w3c.github.io/screen-orientation/#enumdef-orientationlocktype), W3C).

## Exceptions

The specification applies the following failures to `lock()`. Its common safety checks also apply synchronously to `unlock()`.

| Exception | Condition |
|---|---|
| `InvalidStateError` | The document is not a fully active descendant of a top-level traversable with user attention. |
| `SecurityError` | The document is hidden or has the sandboxed orientation lock flag. |
| `NotSupportedError` | The user agent cannot lock to the requested value, or the platform, user preference, or another limitation prevents the attempt. |
| `NotAllowedError` | The user agent requires a pre-lock condition, such as fullscreen or an installed web application, and the document does not meet it. |
| `AbortError` | Another `lock()` request cancels a pending lock request. `unlock()` also cancels it when the screen has an active orientation lock. |

`unlock()` first checks the screen's active orientation lock. If it is `null`, the method returns `undefined` before checking the pending lock promise. Otherwise, a pending lock promise is rejected with `AbortError`, and the user agent applies the default orientation lock ([Screen Orientation](https://w3c.github.io/screen-orientation/#dom-screenorientation-unlock), W3C).

:::caution
The specification rejects `lock()` with `NotAllowedError` when a user agent requires a pre-lock condition and the document does not meet it. Common pre-lock conditions include fullscreen or an installed web application ([Screen Orientation](https://w3c.github.io/screen-orientation/#dom-screenorientation-lock), W3C).
:::

## Examples

The examples check for the relevant Screen Orientation member before using it. Their fallbacks preserve responsive behaviour instead of attempting an unavailable operation.

### Detecting support before locking a viewer

Paste this script into a page. It creates its own button and status output, requests fullscreen before locking, and releases both states on the next click.

```js
const button = document.createElement("button");
const status = document.createElement("output");
button.textContent = "Lock landscape";
document.body.append(button, status);

let locked = false;

button.addEventListener("click", async () => {
  const orientation = screen.orientation;

  if (typeof orientation?.lock !== 'function') {
    const axis = matchMedia("(orientation: portrait)").matches
      ? "portrait"
      : "landscape";
    status.value = `Lock unavailable; responsive layout is ${axis}.`;
    return;
  }

  try {
    if (!locked) {
      if (!document.fullscreenElement) {
        await document.documentElement.requestFullscreen();
      }
      await orientation.lock("landscape");
      locked = true;
      button.textContent = "Unlock orientation";
      status.value = `Locked: ${orientation.type}, ${orientation.angle} degrees.`;
    } else {
      orientation.unlock();
      if (document.fullscreenElement) await document.exitFullscreen();
      locked = false;
      button.textContent = "Lock landscape";
      status.value = "Orientation unlocked.";
    }
  } catch (error) {
    status.value = `${error.name}: orientation was not locked.`;
  }
});
```

The catch branch covers rejected fullscreen and orientation requests. The feature-detection branch leaves layout control to CSS, so the page remains usable when `lock()` is absent.

### Following orientation changes

Read `type` and `angle` again inside the `change` handler because the event signals that those reported values have changed.

```js
function renderOrientation() {
  const current = screen.orientation;
  document.documentElement.dataset.orientation = current.type;
  console.log(`${current.type}: ${current.angle} degrees`);
}

if (screen.orientation) {
  screen.orientation.addEventListener("change", renderOrientation);
  renderOrientation();
} else {
  const portrait = matchMedia("(orientation: portrait)");
  const renderFallback = () => {
    document.documentElement.dataset.orientation = portrait.matches
      ? "portrait"
      : "landscape";
  };
  portrait.addEventListener("change", renderFallback);
  renderFallback();
}
```

The fallback preserves the portrait-or-landscape distinction but does not invent a primary or secondary orientation value that the media query does not provide.

## See also

- [orientation manifest member](/reference/manifest/orientation/)
- [display manifest member](/reference/manifest/display/)
- [Window Management API](/reference/capabilities/window-management/)
- [Screen Orientation](https://w3c.github.io/screen-orientation/) (w3.org)
- [ScreenOrientation interface](https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation) (developer.mozilla.org)
- [ScreenOrientation: lock() method](https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/lock) (developer.mozilla.org)