Skip to content

API in Capabilities

Screen Orientation API (lock and unlock)

Published Updated

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, W3C).

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, MDN; Screen Orientation, W3C).

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, W3C).

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, W3C).

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, W3C).

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

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.

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.

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

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.

Specifications

SpecificationStatus
Screen Orientation: ScreenOrientation interfaceW3C draft
Screen Orientation: lock() methodW3C draft
Screen Orientation: unlock() methodW3C draft