Skip to content

📏 React Native WebView that auto-sizes itself, trims CMS fluff, observes images/iframes/videos, and keeps your parent scroll buttery smooth—no timers, no flicker, just reliable height updates everywhere.

License

Notifications You must be signed in to change notification settings

mCodex/react-native-sized-webview

react-native-sized-webview 📏

npm version npm downloads coverage

React Native WebView that auto-sizes to match its HTML content—whether you load local HTML or full external websites—without manual measurements, timers, or layout flicker.

Important

⚡️ SizedWebView keeps the parent scroll view in charge by disabling the inner WebView scroll and syncing height changes via a lightweight bridge.

Tip

💡 Works out-of-the-box with dynamic CMS pages, FAQs, marketing landers, local HTML snippets, or full external sites.

✨ Highlights

  • 📐 Wrapper-based measurement keeps the WebView content in a dedicated container, so height always reflects the real DOM footprint.
  • 🚀 Modern pipeline powered by ResizeObserver, MutationObserver, visualViewport, and font-load events with graceful fallbacks.
  • 🖼 Media aware: images, iframes, and videos schedule immediate + next-frame re-measures as soon as they finish loading.
  • 🧼 Auto-prunes trailing <br>/empty <p> tags that CMS editors often append, eliminating phantom spacing.
  • 🛡️ Sanity guard clamps runaway heights and retries with the last good value, so flaky pages never lock your layout.
  • 🧵 Keeps the WebView scroll-disabled so outer ScrollViews and gesture handlers stay silky smooth.
  • 🎨 Transparent background by default; style the container however you like.
  • ⚙️ Friendly API with minHeight, containerStyle, and onHeightChange callbacks.
  • 🌲 ESM-first build, fully typed, sideEffects: false for optimal tree shaking.
  • 📱 Verified on iOS, Android, and Expo Go out of the box.

📦 Installation

yarn add react-native-sized-webview react-native-webview
# or
npm install react-native-sized-webview react-native-webview

No native steps are needed beyond the upstream react-native-webview dependency.

🚀 Quick Start

import { SizedWebView } from 'react-native-sized-webview';

const Article = () => (
  <SizedWebView
    minHeight={180}
    source={{
      html: `
        <html>
          <body>
            <h1>Privacy policy</h1>
            <p>Generated by your CMS and sized automatically ✨</p>
          </body>
        </html>
      `,
    }}
    containerStyle={{ borderRadius: 12, overflow: 'hidden' }}
    onHeightChange={(height) => console.log('content height', height)}
  />
);

🧪 Example App

yarn
yarn example ios   # or yarn example android

The example showcases:

  • Auto-sizing dynamic HTML with toggled sections.
  • Live external sites (Marvel, NFL, Google, Wikipedia, The Verge) embedded without layout thrash.
  • Real-time height readouts so you can verify your own endpoints quickly.
  • One code path that works the same on iOS, Android, and Expo Go.

Note

🧪 The demo is built with Expo; swap the uri to test your own pages instantly.

⚙️ API

Prop Type Default Description
minHeight number 0 Minimum height (dp) applied to the container to avoid layout jumps before content loads.
containerStyle StyleProp<ViewStyle> Styles applied to the wrapping View. Use it for padding, borders, or shadows.
onHeightChange (height: number) => void Callback fired whenever a new height is committed. Great for analytics or debugging.
...WebViewProps All remaining props are forwarded to the underlying react-native-webview.

Note

🧩 scrollEnabled defaults to false so sizing remains deterministic. Only enable it if the WebView should manage its own scroll.

🧩 Edge Cases Covered

  • Trailing <br> and empty <p> tags are stripped automatically so CMS exports don’t leave phantom padding.
  • Images, iframes, and videos reschedule measurements the moment they finish loading—perfect for hero images at the end of an article.
  • Wrapper rebuild + fallback timers keep measurements stable even if the remote page rewrites the entire DOM after load.
  • Measurements above safe bounds are retried and then clamped to the last known good height, protecting against broken markup or third-party scripts.

🧠 How It Works

  • Injected bridge re-parents all body children into a dedicated wrapper, trims trailing blanks, and observes DOM mutations, layout changes, font loads, and viewport shifts.
  • Media events (images / iframes / video) trigger immediate + next-frame samples so late assets still report accurate heights.
  • Media elements stay observed via ResizeObserver + decode promises, catching intrinsic size changes without duplicate network requests.
  • Height calculations are debounced via requestAnimationFrame and a short idle timer to prevent resize storms.
  • Measurements arrive through postMessage, then useAutoHeight coalesces them into a single render per frame.
  • Package exports the bridge, hook, and helpers individually, making it easy to build bespoke wrappers when needed.

⚖️ Performance Snapshot

Scenario Plain react-native-webview react-native-sized-webview
Initial render layout shifts Requires timers / manual height guesswork Zero shifts; height resolved before paint
React state updates on content change Manual postMessage plumbing Automatic bridge with RAF + debounce guard
Scrolling in parent ScrollView Nested scroll can fight gestures Parent retains full momentum and gesture priority

Benchmarks were captured on CMS articles up to 3k words in a 60 fps RN dev build. The bridge batches DOM mutations so even long documents resize without thrashing the JS thread.

✅ Testing

yarn test

Jest runs with full coverage collection and enforces 100% statements, branches, functions, and lines across the TypeScript source.

🛠️ Local Development

yarn
yarn lint
yarn typecheck
yarn test --watch=false
yarn example ios   # or yarn example android

This project uses react-native-builder-bob for packaging and release-it for publishing.

🤝 Contributing

Caution

🔬 Before submitting PRs that touch the bridge script, please test the example app on both iOS and Android to catch edge cases with interactive embeds.

📄 License

MIT © Mateus Andrade

About

📏 React Native WebView that auto-sizes itself, trims CMS fluff, observes images/iframes/videos, and keeps your parent scroll buttery smooth—no timers, no flicker, just reliable height updates everywhere.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Sponsor this project