screenfull and the vendor prefixes it hides
Simple wrapper for cross-browser usage of the JavaScript Fullscreen API
At a glance
- What is it?
- screenfull is a 0.7 kB ESM wrapper that folds the prefixed Fullscreen API into request, exit, toggle, and two events. It ships two files, declares itself feature complete, and leaves iPhone, iframes, and page navigation to the browser.
- Who is it for?
- Take screenfull when you want one call instead of three prefixed branches in a bundler based ESM project, and skip it when the target audience may sit on iPhone, inside a third party iframe, or on a browser you cannot transpile for.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 56 days ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- sindresorhus/screenfull7,140 ★ · -1
| Repository | 2026-09-23 | 2026-11-13 |
|---|---|---|
| sindresorhus/screenfull | 7.1k | 7.1k |
-1 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Four prefixed entry points collapse into one request call
The vanilla JavaScript sample in the documentation has to test three method names before it finds the right one, and it passes Element.ALLOW_KEYBOARD_INPUT to the WebKit branch. It also has to reconcile document.fullscreenEnabled, document.mozFullScreenEnabled, and document.documentElement.webkitRequestFullScreen just to decide whether fullscreen is permitted at all.
function requestFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
}
}That whole fan-out moves inside the package, so application code checks screenfull.isEnabled and calls screenfull.request() or screenfull.request(element). The prefixed names remain reachable through screenfull.raw, which exposes requestFullscreen, exitFullscreen, fullscreenElement, fullscreenEnabled, fullscreenchange, and fullscreenerror, so nothing is out of reach for code that needs to step past the wrapper.
The isEnabled flag is the only guard, and an iframe needs three attributes
If your page sits inside an iframe, isEnabled reports false unless that frame carries the allowfullscreen attribute plus webkitallowfullscreen and mozallowfullscreen. Three attributes, written by a parent document you may not control, because a third party frame cannot add them for you. The consequence for a reader is a fullscreen button that renders, takes a click, and does nothing at all, with no exception thrown, because the check is a boolean you have to remember to write. Every documented example wraps its request in an if (screenfull.isEnabled) block rather than calling request() outright, and that guard is the difference between a dead control and a working one.
Without a click, touch, or key press the request is discarded
The browser enters fullscreen only when the call is initiated by a user event such as click, touch, or key. That limit belongs to the platform, and the wrapper passes it through rather than working around it. request(), toggle(), and exit() each return a promise that resolves after the element enters or exits, and the README pairs them with an 'error' event for failures.
import screenfull from 'screenfull';
if (screenfull.isEnabled) {
screenfull.on('error', event => {
console.error('Failed to enable fullscreen', event);
});
}Two events, one alias each, and off needs the same reference
The event surface is exactly two names, 'change' and 'error', each with a method alias in .onchange and .onerror. Removal takes the same event name and the same function you registered, so a named handler works and an inline arrow passed straight into .on does not, because no reference survives to hand back. There is no documented way to strip every listener in one call.
import screenfull from 'screenfull';
screenfull.off('change', callback);import screenfull from 'screenfull';
if (screenfull.isEnabled) {
screenfull.on('change', () => {
console.log('Am I fullscreen?', screenfull.isFullscreen ? 'Yes' : 'No');
});
}In a single page app that remounts a toolbar you therefore keep stable named handlers in module scope, or you accumulate one listener per mount.
Navigating to a new page while fullscreen is refused by the browser
screenfull cannot move your user to another address while the page is fullscreen, and the block does not live in JavaScript. The FAQ entry states that browsers refuse this for security reasons, then calls its own workaround dirty: build an iframe that fills the screen and navigate inside that instead. If a fullscreen player has to follow a user to a new route, screenfull offers no path to it, and you end up designing around an iframe whose styling you do not control.
ESM only, and version 5.2.0 is the way back
package.json sets type to module, exports only ./index.js, and asks for Node ^14.13.1 || >=16.0.0. There is no CommonJS build in the tarball, since the files array holds index.js and index.d.ts and nothing else. The way out is stated plainly: if you cannot use ESM, or you need to support older browsers without transpilation, use version 5.2.0. An older build also sits on cdnjs at version 5.1.0, so a plain script tag path exists but trails the current release. Installing and the first call take four lines.
npm install screenfullimport screenfull from 'screenfull';
if (screenfull.isEnabled) {
screenfull.request();
}The default target is the html element, and the returned promise resolves after the element is actually fullscreen.
iPhone gets nothing, and the blame belongs to the browser
The support note is blunt: Safari works on desktop and on iPad, but not on iPhone, and that is a limitation in the browser rather than in the wrapper. The top of the page carries the same warning in bold and points down to the support section. For a reader shipping a media viewer or a slide deck, that means the fullscreen path has to degrade by itself, with no browser chrome to hide, no orientation change to react to, and a layout that survives a viewport which never resizes.
Feature complete, two shipped files, and xo plus tsd
The page states that the package is feature complete and that no new features will be accepted, which is why the API stops at request, exit, toggle, on, off, onchange, onerror, isFullscreen, element, isEnabled, and raw. The newest tagged release is v6.0.2 from 2022-06-19, while the most recent push to the repository landed on 2026-09-18, so the tree moves without cutting new tags. Weight is the other selling point at 0.7 kB gzipped. Verification is thin but specific: the test script is xo && tsd, xo is configured for the node and browser environments, and index.test-d.ts sits next to the demo in index.html.
Editorial conclusion
Take screenfull when you want one call instead of three prefixed branches in a bundler based ESM project, and skip it when the target audience may sit on iPhone, inside a third party iframe, or on a browser you cannot transpile for.
Frequently asked questions
Does screenfull work on iPhone Safari?
No. Safari is supported on desktop and iPad but not on iPhone, and the README calls that a limitation in the browser rather than in the wrapper.
Can screenfull navigate to a new page while fullscreen is active?
No, browsers block it for security reasons. The suggested workaround is an iframe that fills the screen with the navigation happening inside it.
What does screenfull require when my page is inside an iframe?
The frame needs an allowfullscreen attribute plus webkitallowfullscreen and mozallowfullscreen, otherwise isEnabled returns false.
Why does screenfull ask for Node 14.13.1 or newer?
package.json sets type to module and engines to ^14.13.1 || >=16.0.0, so the package is ESM only and ships no CommonJS build.
How do I remove a screenfull event listener?
Call screenfull.off('change', callback) with the same event name and the same function you registered with .on, and use .off('error', callback) for error handlers.
What does the screenfull npm package actually ship?
package.json lists index.js and index.d.ts in its files array, and the stated gzipped weight is 0.7 kB.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/sindresorhus-screenfull)Star history chart for your README
[](https://hysenlabs.com/projects/sindresorhus-screenfull)Was this useful?