Skip to content

@tank/browser-polyfills

1.0.0

Diagnose and fix browser compatibility issues in Next.js apps. Covers Safari/iOS Safari JS polyfills, CSS workarounds, Next.js polyfill config (App Router + Pages Router), browserslist, feature detection, and safe polyfill delivery. Triggers: polyfill, Safari broken, works in Chrome not Safari, iOS Safari bug, browserslist, cross-browser, caniuse, requestIdleCallback, 100vh Safari, input zoom iOS, backdrop-filter Safari, Safari date parsing, polyfill.io alternative.


name: browser-polyfills description: | Diagnose and fix browser compatibility issues in Next.js apps targeting Safari, iOS Safari, and Firefox. Covers JavaScript API polyfills, CSS workarounds, Next.js polyfill configuration (App Router and Pages Router), browserslist setup, feature detection, and safe polyfill delivery. Synthesizes caniuse.com data, WebKit Bug Tracker, MDN Web Docs, and production Next.js codebase patterns.

Trigger phrases: "polyfill", "Safari broken", "works in Chrome not Safari", "iOS Safari bug", "WebKit issue", "browserslist", "browser compatibility", "cross-browser", "caniuse", "feature detection", "@supports", "CSS.supports", "requestIdleCallback", "100vh Safari", "dvh", "svh", "input zoom iOS", "backdrop-filter Safari", "Safari date parsing", "scroll lock iOS", "position sticky Safari", "gap flexbox Safari", "@next/polyfill", "polyfill.io alternative", "Safari PWA", "smooth scroll Safari", "Safari service worker"

Browser Polyfills for Next.js

Core Philosophy

  • Fix what's broken, not what's theoretical. Check caniuse before adding polyfills.
  • Load polyfills conditionally. Modern browsers should not pay for Safari's gaps.
  • Safari on iOS is the primary target. All iOS browsers use WebKit, so a Safari bug affects Chrome on iPhone too.
  • Prefer CSS workarounds over JavaScript polyfills when possible — zero runtime cost.
  • Never use polyfill.io — it was compromised in 2024. Self-host or use Cloudflare's mirror.

Quick-Start: Diagnosing What Broke

"My app works in Chrome but breaks in Safari"

  1. Open Safari DevTools (or WebKit Inspector on iOS via Mac)
  2. Check the Console for errors — note the API name
  3. Look up the API in references/safari-js-polyfills.md for the compatibility matrix
  4. If it's a CSS issue (layout, styling), check references/safari-css-workarounds.md
  5. Add the polyfill via instrumentation-client.ts (App Router) or _app.tsx (Pages Router)
  6. See references/nextjs-polyfill-config.md for configuration

"Dates show as Invalid Date on Safari"

Safari is strict about date string formats. new Date('2025-01-15') works in Chrome but can break in Safari without the T separator. -> See references/safari-react-bugs.md for safe patterns and date-fns usage.

"Input fields zoom the page on iOS"

Any <input> with font-size < 16px triggers iOS auto-zoom on focus. -> See references/safari-react-bugs.md for the CSS fix.

"100vh doesn't work right on iOS"

iOS Safari's dynamic address bar causes 100vh to include the hidden chrome. -> See references/safari-react-bugs.md for the layered CSS + JS fallback.

"I need to set up polyfills from scratch in Next.js"

-> See references/nextjs-polyfill-config.md for the full configuration guide.

Decision Trees

What to Polyfill

SymptomLikely CauseReference
JS error in Safari consoleMissing APIreferences/safari-js-polyfills.md
Layout broken on iOS onlyCSS gap / viewportreferences/safari-css-workarounds.md
Date shows NaN or InvalidDate parsingreferences/safari-react-bugs.md
Page zooms on input focusFont-size < 16pxreferences/safari-react-bugs.md
Scroll doesn't lock on modaliOS body overflow bugreferences/safari-react-bugs.md
Firefox-specific layout issueScrollbar / Houdinireferences/firefox-quirks.md
Bundle too largeUnnecessary polyfillsreferences/polyfill-delivery.md

Where to Add Polyfills in Next.js

RouterEntry PointWhen
App Routerinstrumentation-client.tsRuns before hydration — best for global polyfills
App RouterDynamic import() in useEffectHeavy polyfills needed by specific components only
Pages Routerimport '../polyfills' in _app.tsxTop-level import, runs before anything else
Either<Script strategy="beforeInteractive">External CDN polyfill scripts

How to Load Polyfills

StrategyWhen to UseBundle Impact
Static import in entry fileAlways-needed polyfills (requestIdleCallback)Always loaded
Dynamic import with feature detectionHeavy polyfills for older browsers onlyLoaded on demand
CDN script tagThird-party polyfill serviceExternal, cached
browserslist narrowingEliminate auto-injected polyfillsReduces bundle 10-15 KiB

Priority Polyfills for Safari (2026)

PriorityAPI / FeatureAction
CriticalrequestIdleCallbackAlways polyfill — Safari will never ship this
CriticalDate string parsingUse ISO 8601 with T separator, or use date-fns
CriticalInput zoom preventionCSS: font-size: 16px on inputs
Criticalpolyfill.io removalReplace with Cloudflare mirror or self-host
High-webkit-backdrop-filterAdd prefix alongside standard property
Highdvh / viewport heightLayered fallback: 100vh then 100dvh then JS
HighiOS scroll lockUse position: fixed pattern, not overflow: hidden
Mediumsmoothscroll-polyfillFor Safari < 15.4 smooth scroll support
MediumFirefox scrollbar stylingDual scrollbar-width + ::-webkit-scrollbar
LowTemporal APIDo not use — Safari has no timeline. Use date-fns

Reference Files

FileContents
references/safari-js-polyfills.mdJS API compatibility matrix, polyfill packages, feature detection code
references/safari-css-workarounds.mdCSS bugs, vendor prefixes, viewport units, sticky positioning
references/nextjs-polyfill-config.mdinstrumentation-client.ts, browserslist, SWC, App/Pages Router setup
references/safari-react-bugs.mdDate parsing, input zoom, 100vh, scroll lock, modal bugs, PWA issues
references/polyfill-delivery.mdpolyfill.io alternative, feature detection, bundle impact, security
references/firefox-quirks.mdScrollbar styling, Houdini gaps, FormData quirks, late feature support

Command Palette

Search skills, docs, and navigate Tank