Use ponyfill.com for linking here.
A ponyfill is an implementation of a standard, but without pretending to be it.
Unlike polyfills, ponyfills don't pretend to be the native API. They offer the same functionality through explicit imports and usage, keeping your code predictable and side-effect free.
In JavaScript, a polyfill adds missing features by monkey patching the environment, typically by modifying globals like Array.prototype
, Object
, or window
. This approach creates several problems:
- The polyfill is only partially spec-compliant (sometimes unavoidable)
- The spec changes
- Another library polyfills the same thing differently
In general, you should not modify APIs you don’t own. Ponyfills avoid this entirely by staying pure.
- JavaScript ponyfill: Exports functionality via a normal module, doesn’t patch anything
- HTML ponyfill: Uses custom elements or classes to emulate new features
- CSS ponyfill: Uses custom properties to simulate proposed syntax
Feature | Polyfill | Ponyfill |
---|---|---|
Patches global environment? | Yes | No |
Aims to match spec exactly? | Yes | Often |
Meant to be removed later? | Yes | Not necessarily |
Causes global side effects? | Yes | No |
Ponyfills are clear. Explicit. Honest. You use them directly and deliberately.
Number.isNaN ??= function (value) {
return value !== value;
};
import 'is-nan-polyfill';
Number.isNaN(5);
export default function isNaN(value) {
return value !== value;
};
import isNanPonyfill from 'is-nan-ponyfill';
isNanPonyfill(5);
<!-- Instead of a future <card> element -->
<card-ponyfill>
<h2 slot="title">Hello</h2>
</card-ponyfill>
<script>
customElements.define('card-ponyfill', class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<div class="card">${this.innerHTML}</div>`;
}
});
</script>
/* Instead of future syntax like @container */
:root {
--container-sm: 480px;
--container-lg: 768px;
}
.responsive-text[data-container='small'] {
font-size: 0.875rem;
}
.responsive-text[data-container='large'] {
font-size: 1.125rem;
}
<div class="responsive-text" data-container="small">Responsive text</div>
Ponyfills should avoid relying on native APIs unless unavoidable because:
- Native APIs may behave inconsistently
- Bugs or spec changes undermine confidence
- Reimplementing avoids dependency on the environment
Use native APIs only when:
- No alternative exists
- Reimplementation would hurt performance or bundle size
- Read the spec or explainer
- Implement the feature locally, without patching anything global
- Avoid assuming native API correctness unless necessary
- Write tests
- Publish a module or package
- Add
ponyfill
to the keywords field - Link to ponyfill.com in your readme
- Ponyfill definition - Silicon Valley Dictionary
- Polyfills or Ponyfills? - Pony Foo
- Polyfill, Ponyfill and Prollyfill - Kikobeats
To the extent possible under law, Sindre Sorhus has waived all copyright and related or neighboring rights to this work.
Header based on work by Mary Winkler.