├── .editorconfig ├── .eslintrc.json ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ ├── nodejs.yml │ └── publish.yml ├── .gitignore ├── CODEOWNERS ├── LICENSE ├── README.md ├── docs ├── favicon.ico └── index.html ├── package-lock.json ├── package.json ├── src ├── clipboarditem.ts ├── element-checkvisibility.ts ├── index.ts ├── navigator-clipboard.ts ├── promise-withResolvers.ts └── requestidlecallback.ts ├── test ├── clipboarditem.js ├── element-checkvisibility.js ├── index.js ├── navigator-clipboard.js ├── promise-withResolvers.js └── requestidlecallback.js ├── tsconfig.json └── web-test-runner.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | max_line_length = 120 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": ["github"], 4 | "extends": ["plugin:github/recommended", "plugin:github/typescript", "plugin:github/browser"], 5 | "rules": { 6 | "no-invalid-this": "off", 7 | "@typescript-eslint/no-invalid-this": ["error"], 8 | "import/extensions": ["error", "ignorePackages"], 9 | "import/no-namespace": "off", 10 | "import/no-unresolved": "off", 11 | "@typescript-eslint/consistent-type-imports": ["error", {"prefer": "type-imports"}] 12 | }, 13 | "overrides": [ 14 | { 15 | "files": "test/*", 16 | "rules": { 17 | "@typescript-eslint/no-empty-function": "off" 18 | }, 19 | "globals": { 20 | "chai": false, 21 | "expect": false, 22 | "globalThis": false 23 | }, 24 | "env": { 25 | "mocha": true 26 | } 27 | }, 28 | { 29 | "files": "*.cjs", 30 | "env": { 31 | "node": true 32 | }, 33 | "rules": { 34 | "import/no-commonjs": "off", 35 | "filenames/match-regex": "off", 36 | "@typescript-eslint/no-var-requires": "off" 37 | } 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup project 2 | description: Sets up the repo code, Node.js, and npm dependencies 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: Set up Node.js 8 | uses: actions/setup-node@v2 9 | with: 10 | node-version: '16.x' 11 | cache: npm 12 | registry-url: https://registry.npmjs.org 13 | - name: Install npm dependencies 14 | run: npm ci 15 | shell: bash 16 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: 22 16 | registry-url: https://registry.npmjs.org/ 17 | cache: npm 18 | - run: npm ci 19 | - run: npm test 20 | env: 21 | CI: true 22 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: read 12 | id-token: write 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-node@v4 16 | with: 17 | node-version: 22 18 | registry-url: https://registry.npmjs.org/ 19 | cache: npm 20 | - run: npm ci 21 | - run: npm run build 22 | - run: npm test 23 | - run: npm version ${TAG_NAME} --git-tag-version=false 24 | env: 25 | TAG_NAME: ${{ github.event.release.tag_name }} 26 | - run: npm whoami; npm --ignore-scripts publish --provenance 27 | env: 28 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @github/web-systems-reviewers 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GitHub 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # browser-support 2 | 3 | This library allows websites to maintain compatibility with older browsers, which do not implement newer features. It does so using [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill) for small new features, plus functions to determine if a browser supports a set of features natively or with polyfills. 4 | 5 | If you would like to see what features the browser you are currently using implements, you [can visit the documentation site](https://github.github.com/browser-support/) which displays a compatibility table that detects which features are natively supported in your browser. 6 | 7 | ### How is this used on GitHub? 8 | 9 | We use all of these polyfills on GitHub.com. We also use the `isSupported()` function to determine if the browser meets a minimum set of functionality which we expect, browser that return false from `isSupported()` do not send errors or statistics to our backend monitoring. 10 | 11 | ## Installation 12 | 13 | ``` 14 | $ npm install @github/browser-support 15 | ``` 16 | 17 | ## Usage 18 | 19 | ### JS 20 | 21 | ```js 22 | import {isSupported, isPolyfilled, apply} from '@github/browser-support' 23 | 24 | // Check if a browser is supported 25 | if (!isSupported()) { 26 | apply() 27 | console.assert(isSupported() === true) 28 | console.assert(isPolyfilled() === true) 29 | } 30 | ``` 31 | 32 | ## Development 33 | 34 | ``` 35 | npm install 36 | npm test 37 | ``` 38 | 39 | ## Upgrading browser-support in Dotcom 40 | 41 | During upgrades, it is crucial to ensure that browser error reporting to Sentry is not disrupted. Use the following steps to validate this functionality: 42 | 43 | ### Review lab testing 44 | - Create a PR to upgrade the `browser-support` version in Dotcom. 45 | - Trigger a browser error from your `review-lab` instance and confirm it is reported in Sentry: 46 | - Append `#b00m` to your `review-lab` URL (e.g. `https://branchname.review-lab.github.com#b00m`) and refresh the page. 47 | - Confirm the error is reported in [review-lab Sentry](https://github.sentry.io/issues/?environment=review-lab&groupStatsPeriod=auto&project=1890375&query=b00m&referrer=issue-list&statsPeriod=5m). 48 | - Perform these steps in Chrome, Firefox, Edge, and Opera. Note: Errors are currently not reported in Safari due to an [open issue](https://github.com/github/web-systems/issues/3162). 49 | 50 | ### Production deployment 51 | 52 | - Check the [browser-reporting](https://app.datadoghq.com/monitors/168685099) monitor. 53 | - If the rate of reported browser errors drops, the monitor will trigger an alert in the [#web-systems-ops](https://github-grid.enterprise.slack.com/archives/C046W1V95FV) channel. 54 | - After deploying to canary: 55 | - Trigger a browser error by appending `#b00m` to your URL. 56 | - Confirm the error is reported in [canary Sentry](https://github.sentry.io/issues/?environment=canary&groupStatsPeriod=auto&project=1890375&query=b00m&referrer=issue-list&statsPeriod=5m). 57 | - After deploying to production: 58 | - Trigger a browser error by appending `#b00m` to your URL. 59 | - Confirm the error is reported in [production Sentry](https://github.sentry.io/issues/?environment=production&groupStatsPeriod=auto&project=1890375&query=b00m&referrer=issue-list&statsPeriod=5m). 60 | - Check the [browser-reporting monitor](https://app.datadoghq.com/monitors/168685099) to ensure there are no anomalies in the error reporting rate. 61 | 62 | ## Contributing 63 | 64 | ### Adding polyfills 65 | 66 | Please do not add any polyfills for ECMA features that are Stage 3 or below. We _only_ wish to polyfill features from ECMAScript that are Stage 4 (about to be included in a new years specification) or already specified. 67 | 68 | ### Removing polyfills 69 | 70 | Polyfills should only be removed after consulting with the `@github/web-systems` who will determine if a polyfill can be removed. This code is designed to be kept lightweight, we do not want to ship dozens of kb of polyfills. 71 | 72 | As a polyfill is removed, it may be worth adding feature detection to the `baseSupport` const, to ensure that our baseline moves with our browser support matrix. 73 | 74 | ## License 75 | 76 | Distributed under the MIT license. See LICENSE for details. 77 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/browser-support/c616162d8f816c7b2d16afbabbd8c59d1b6998e6/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |160 | The table below details some of the client-side ECMAScript features we use to provide the largest and most 161 | advanced development platform in the world. 162 |
163 |182 | | ... | 183 |Google Chrome | 184 |Microsoft Edge | 185 |Mozilla Firefox | 186 |Apple Safari | 187 |Opera | 188 |Samsung Internet | 189 |
---|---|---|---|---|---|---|---|
194 | | Base Objects & Functions |
195 | ||||||
198 |
199 | queueMicrotask Function
200 |
201 | |
202 | ! |
203 | 71+ |
204 | 79+ |
205 | 69+ |
206 | 12.1+ |
207 | 58+ |
208 | 10.0+ |
209 |
212 |
213 | HTMLDialogElement Constructor
214 |
215 | |
216 | ! |
217 | 37+ |
218 | 79+ |
219 | 98+ |
220 | 15.4+ |
221 | 24+ |
222 | 4.0+ |
223 |
226 |
227 | globalThis Object
228 |
229 | |
230 | ! |
231 | 71+ |
232 | 79+ |
233 | 65+ |
234 | 12.1+ |
235 | 58+ |
236 | 10.0+ |
237 |
240 |
243 | Object.fromEntries
244 |
245 | |
246 | ! |
247 | 73+ |
248 | 79+ |
249 | 63+ |
250 | 12.1+ |
251 | 60+ |
252 | 11.0+ |
253 |
256 |
257 | Array.flatMap
258 |
259 | |
260 | ! |
261 | 69+ |
262 | 79+ |
263 | 62+ |
264 | 12+ |
265 | 56+ |
266 | 10.0+ |
267 |
270 |
271 | String.trimEnd
272 |
273 | |
274 | ! |
275 | 66+ |
276 | 79+ |
277 | 61+ |
278 | 12+ |
279 | 53+ |
280 | 9.0+ |
281 |
284 |
287 | String.matchAll
288 |
289 | |
290 | ! |
291 | 73+ |
292 | 79+ |
293 | 67+ |
294 | 13+ |
295 | 60+ |
296 | 11.0+ |
297 |
300 |
303 | String.replaceAll
304 |
305 | |
306 | ! |
307 | 85+ |
308 | 85+ |
309 | 77+ |
310 | 13.1+ |
311 | 71+ |
312 | 14.0+ |
313 |
316 |
319 | Promise.allSettled
320 |
321 | |
322 | ! |
323 | 76+ |
324 | 79+ |
325 | 71+ |
326 | 13+ |
327 | 63+ |
328 | 12.0+ |
329 |
332 |
333 | Promise.any
334 |
335 | |
336 | ! |
337 | 85+ |
338 | 85+ |
339 | 79+ |
340 | 14+ |
341 | 71+ |
342 | 14+ |
343 |
346 |
349 | String.prototype.at
350 |
351 | |
352 | ! |
353 | 92+ |
354 | 92+ |
355 | 90+ |
356 | 15.4+ |
357 | 65+ |
358 | 16.0+ |
359 |
362 |
365 | Array.prototype.at
366 |
367 | |
368 | ! |
369 | 92+ |
370 | 92+ |
371 | 90+ |
372 | 15.4+ |
373 | 65+ |
374 | 16.0+ |
375 |
378 |
379 | Object.hasOwn
380 |
381 | |
382 | ! |
383 | 93+ |
384 | 93+ |
385 | 92+ |
386 | 15.4+ |
387 | 79+ |
388 | 17.0+ |
389 |
392 |
393 | AbortSignal.abort
394 |
395 | |
396 | ! |
397 | 93+ |
398 | 93+ |
399 | 88+ |
400 | 15+ |
401 | 79+ |
402 | 17.0+ |
403 |
406 |
407 | AbortSignal.timeout
408 |
409 | |
410 | ! |
411 | 103+ |
412 | 103+ |
413 | 100+ |
414 | 16+ |
415 | 89+ |
416 | 16+ |
417 |
420 |
421 | AggregateError
422 |
423 | |
424 | ! |
425 | 85+ |
426 | 85+ |
427 | 79+ |
428 | 14+ |
429 | 71+ |
430 | 14.0+ |
431 |
434 |
435 | BroadcastChannel
436 |
437 | |
438 | ! |
439 | 54+ |
440 | 79+ |
441 | 38+ |
442 | 15.4+ |
443 | 41+ |
444 | 6.0+ |
445 |
448 |
449 | Crypto.randomUUID
450 |
451 | |
452 | ! |
453 | 92+ |
454 | 92+ |
455 | 95+ |
456 | 15.4+ |
457 | 78+ |
458 | 16.0+ |
459 |
462 |
463 | Element.replaceChildren
464 |
465 | |
466 | ! |
467 | 86+ |
468 | 86+ |
469 | 78+ |
470 | 14+ |
471 | 72+ |
472 | 14.0+ |
473 |
476 |
477 | HTMLFormElement.requestSubmit
478 |
479 | |
480 | ! |
481 | 76+ |
482 | 79+ |
483 | 75+ |
484 | 16+ |
485 | 63+ |
486 | 12.0+ |
487 |
490 | | Polyfilled Features |
491 | ||||||
494 |
495 | ClipboardItem
496 |
497 | |
498 | * |
499 | 66+ † |
500 | 79+ † |
501 | 87+ † |
502 | 13.1+ |
503 | 53+ † |
504 | 9.0+ † |
505 |
508 |
509 | Element.checkVisibility
510 |
511 | |
512 | * |
513 | 105+ |
514 | 105+ |
515 | 106+ |
516 | 17.4+ |
517 | 91+ |
518 | 20.0+ |
519 |
522 |
523 | navigator.clipboard
524 |
525 | |
526 | * |
527 | 86+ |
528 | 79+ |
529 | 63+ † |
530 | 13.1+ |
531 | 63+ † |
532 | 12.0+ † |
533 |
536 |
537 | requestIdleCallback
538 |
539 | |
540 | * |
541 | 47+ |
542 | 79+ |
543 | 55+ |
544 | * |
545 | 34+ |
546 | 5.0+ |
547 |
550 |
551 | HTMLElement.popover
552 |
553 | |
554 | * |
555 | 114+ |
556 | 114+ |
557 | 125+ |
558 | 17+ |
559 | 100+ |
560 | 23.0+ |
561 |
564 |
565 | HTMLElement.popover = 'hint'
566 |
567 | |
568 | * |
569 | 114+ |
570 | 114+ |
571 | 125+ |
572 | 17+ |
573 | + |
574 | 12.0+ |
575 |
578 |
579 | beforetoggle on Dialog
580 |
581 | |
582 | * |
583 | 132+ |
584 | 132+ |
585 | 133+ |
586 | * |
587 | 117+ |
588 | * |
589 |
592 |
593 | command & commandfor
594 |
595 | |
596 | * |
597 | 135+ |
598 | * |
599 | * |
600 | * |
601 | * |
602 | * |
603 |
606 | | Native Syntax |
607 | ||||||
610 |
613 | Exponentiation Operator
614 |
615 | |
616 | ! |
617 | 52+ |
618 | 14+ |
619 | 52+ |
620 | 10.1+ |
621 | 39+ |
622 | 6.0+ |
623 |
626 |
629 | Object Rest/Spead
630 |
631 | |
632 | ! |
633 | 60+ |
634 | 79+ |
635 | 55+ |
636 | 11.1+ |
637 | 47+ |
638 | 8.2+ |
639 |
642 |
645 | RegExp Named Capture Groups
646 |
647 | |
648 | ! |
649 | 64+ |
650 | 79+ |
651 | 78+ |
652 | 11.1+ |
653 | 51+ |
654 | 9.0+ |
655 |
658 |
659 | Async Generators & for await
660 |
661 | |
662 |
665 | !
666 | |
667 | 63+ |
668 | 79+ |
669 | 57+ |
670 | 11+ |
671 | 50+ |
672 | 8.0+ |
673 |
676 |
677 | Optional Catch Binding
678 |
679 | |
680 | ! |
681 | 66+ |
682 | 79+ |
683 | 58+ |
684 | 11.1+ |
685 | 53+ |
686 | 9.0+ |
687 |
690 |
691 | Optional Chaining Operator (?.)
692 |
693 | |
694 | ! |
695 | 80+ |
696 | 80+ |
697 | 74+ |
698 | 13.1+ |
699 | 67+ |
700 | 13.0+ |
701 |
704 |
707 | Nullish Coalescing Operator (??)
708 |
709 | |
710 | ! |
711 | 80+ |
712 | 80+ |
713 | 72+ |
714 | 13.1+ |
715 | 67+ |
716 | 13.0+ |
717 |
720 |
723 | Logical Nullish Assignment (??=)
724 |
725 | |
726 | ** |
727 | 85+ |
728 | 85+ |
729 | 79+ |
730 | 14+ |
731 | 71+ |
732 | 14.0+ |
733 |
736 |
739 | Public Class Fields
740 |
741 | |
742 | ** |
743 | 72+ |
744 | 79+ |
745 | 69+ |
746 | 14.1+ |
747 | 60+ |
748 | 11.0+ |
749 |
752 |
753 | Private Class Fields
754 |
755 | |
756 | ** |
757 | 74+ |
758 | 79+ |
759 | 90+ |
760 | 14.1+ |
761 | 62+ |
762 | 11.0+ |
763 |
766 |
769 | Static Class Blocks
770 |
771 | |
772 | ** |
773 | 94+ |
774 | 94+ |
775 | 93+ |
776 | 16.4+ |
777 | 80+ |
778 | 17.0+ |
779 |
782 | | Transpiled Native Syntax |
783 | ||||||
786 |
787 | Decorators
788 |
789 | |
790 | ** |
791 | ** |
792 | ** |
793 | ** |
794 | ** |
795 | ** |
796 | ** |
797 |