What are JavaScript polyfills for?
TL;DR
Polyfills implement a missing JavaScript or Web API in environments that do not provide it. Choose them from an explicit support matrix and feature tests, load only the required modules, and prefer maintained implementations because matching specification edge cases is difficult. A transpiler rewrites syntax; it does not by itself add runtime objects such as Promise, URL, or new array methods.
They can be implemented manually or included through libraries and are often used in conjunction with feature detection.
Common use cases include:
- New JavaScript Methods: For example,
Array.prototype.includes(),Object.assign(), etc. - New APIs: Such as
fetch(),Promise,IntersectionObserver, etc. Modern browsers support these now, but for a long time they had to be polyfilled.
A commonly used polyfill library is:
-
core-js: A modular standard library for JavaScript which includes polyfills for a wide range of ECMAScript features.import 'core-js/actual/array/flat-map'; // With this, Array.prototype.flatMap is available to be used.[1, 2].flatMap((it) => [it, it]); // => [1, 1, 2, 2]
Prefer installing maintained polyfills as project dependencies and bundling them with your application instead of loading executable code from a third-party polyfill service at runtime.
Polyfills in JavaScript
Polyfills in JavaScript are pieces of code (usually JavaScript) that provide modern functionality on older browsers that do not natively support it. They enable developers to use newer features of the language and APIs while maintaining compatibility with older environments.
How polyfills work
Polyfills detect if a feature or API is missing in a browser and provide a custom implementation of that feature using existing JavaScript capabilities. This allows developers to write code using the latest JavaScript features and APIs without worrying about browser compatibility issues.
For example, an application can conditionally load a maintained ResizeObserver fallback before starting code that needs it:
if (!('ResizeObserver' in globalThis)) {await import('./resize-observer-polyfill.js');}
This runs in an ES module because it uses top-level await. The fallback still needs tests in the actual target browsers; feature presence alone does not prove identical behavior for every edge case.
Implementing polyfills
- Identify the missing feature: Determine if the feature is compatible with the target browsers or detect its presence using feature detection methods like
typeof,in, orwindow. - Write the fallback implementation: Develop the fallback implementation that provides similar functionality, either using a pre-existing polyfill library or pure JavaScript code.
- Test the polyfill: Thoroughly test the polyfill to ensure it functions as intended across different contexts and browsers.
- Implement the polyfill: Enclose the code that uses the missing feature in an if statement that checks for feature support. If not supported, run the polyfill code instead.
Considerations
- Selective loading: Load only the features required by the application's supported environments. Conditional loading can save bytes for newer clients but adds another request and code path.
- Feature detection: Perform feature detection before applying a polyfill to avoid overwriting native implementations or applying unnecessary polyfills.
- Size and performance: Polyfills can increase the JavaScript bundle size, so minification and compression techniques should be used to mitigate this impact.
- Existing libraries: Consider using existing libraries and tools that offer comprehensive polyfill solutions for multiple features, handling feature detection, conditional loading, and fallbacks efficiently.
- Global mutation: Many polyfills patch globals or prototypes. A “pure” library helper may be safer for embeddable code that must not change its host page.
- Unpolyfillable behavior: Some syntax, security properties, rendering behavior, and platform capabilities cannot be reproduced faithfully with JavaScript alone. Use progressive enhancement or an alternative experience.
Libraries for polyfills
-
core-js: A modular standard library for JavaScript which includes polyfills for a wide range of ECMAScript features.import 'core-js/actual/array/flat-map'; // With this, Array.prototype.flatMap is available to be used.[1, 2].flatMap((it) => [it, it]); // => [1, 1, 2, 2]
Prefer installing maintained polyfills as project dependencies and bundling them with your application instead of loading executable code from a third-party polyfill service at runtime.