|
1 | | -# react-native-webview-sized |
| 1 | +# react-native-sized-webview 📏 |
2 | 2 |
|
3 | | -... |
| 3 | +[](https://www.npmjs.com/package/react-native-sized-webview) |
| 4 | +[](https://www.npmjs.com/package/react-native-sized-webview) |
| 5 | +[](#-testing) |
4 | 6 |
|
5 | | -## Installation |
| 7 | +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. |
6 | 8 |
|
| 9 | +> [!IMPORTANT] |
| 10 | +> ⚡️ `SizedWebView` keeps the parent scroll view in charge by disabling the inner WebView scroll and syncing height changes via a lightweight bridge. |
| 11 | +
|
| 12 | +> [!TIP] |
| 13 | +> 💡 Works out-of-the-box with dynamic CMS pages, FAQs, marketing landers, local HTML snippets, or full external sites. |
| 14 | +
|
| 15 | +## ✨ Highlights |
| 16 | + |
| 17 | +- 📐 Auto-measures rendered HTML height on every DOM mutation or resize. |
| 18 | +- 🚀 Modern pipeline powered by `ResizeObserver`, `MutationObserver`, `visualViewport`, and font-load events with graceful fallbacks. |
| 19 | +- 🧵 Keeps the WebView scroll-disabled so outer `ScrollView`s and gesture handlers stay silky smooth. |
| 20 | +- 🎨 Transparent background by default; style the container however you like. |
| 21 | +- ⚙️ Friendly API with `minHeight`, `containerStyle`, and `onHeightChange` callbacks. |
| 22 | +- 🌲 ESM-first build, fully typed, `sideEffects: false` for optimal tree shaking. |
| 23 | +- 📱 Verified on iOS, Android, and Expo Go out of the box. |
| 24 | + |
| 25 | +## 📦 Installation |
| 26 | + |
| 27 | +```sh |
| 28 | +yarn add react-native-sized-webview react-native-webview |
| 29 | +# or |
| 30 | +npm install react-native-sized-webview react-native-webview |
| 31 | +``` |
| 32 | + |
| 33 | +No native steps are needed beyond the upstream `react-native-webview` dependency. |
| 34 | + |
| 35 | +## 🚀 Quick Start |
| 36 | + |
| 37 | +```tsx |
| 38 | +import { SizedWebView } from 'react-native-sized-webview'; |
| 39 | + |
| 40 | +const Article = () => ( |
| 41 | + <SizedWebView |
| 42 | + minHeight={180} |
| 43 | + source={{ |
| 44 | + html: ` |
| 45 | + <html> |
| 46 | + <body> |
| 47 | + <h1>Privacy policy</h1> |
| 48 | + <p>Generated by your CMS and sized automatically ✨</p> |
| 49 | + </body> |
| 50 | + </html> |
| 51 | + `, |
| 52 | + }} |
| 53 | + containerStyle={{ borderRadius: 12, overflow: 'hidden' }} |
| 54 | + onHeightChange={(height) => console.log('content height', height)} |
| 55 | + /> |
| 56 | +); |
| 57 | +``` |
| 58 | + |
| 59 | +## 🧪 Example App |
7 | 60 |
|
8 | 61 | ```sh |
9 | | -npm install react-native-webview-sized |
| 62 | +yarn |
| 63 | +yarn example ios # or yarn example android |
10 | 64 | ``` |
11 | 65 |
|
| 66 | +The example showcases: |
12 | 67 |
|
13 | | -## Usage |
| 68 | +- Auto-sizing dynamic HTML with toggled sections. |
| 69 | +- Live external sites (Marvel, NFL, Google, Wikipedia, The Verge) embedded without layout thrash. |
| 70 | +- Real-time height readouts so you can verify your own endpoints quickly. |
14 | 71 |
|
| 72 | +> [!NOTE] |
| 73 | +> 🧪 The demo is built with Expo; swap the `uri` to test your own pages instantly. |
15 | 74 |
|
16 | | -```js |
17 | | -import { multiply } from 'react-native-webview-sized'; |
| 75 | +## ⚙️ API |
18 | 76 |
|
19 | | -// ... |
| 77 | +| Prop | Type | Default | Description | |
| 78 | +| --- | --- | --- | --- | |
| 79 | +| `minHeight` | `number` | `0` | Minimum height (dp) applied to the container to avoid layout jumps before content loads. | |
| 80 | +| `containerStyle` | `StyleProp<ViewStyle>` | — | Styles applied to the wrapping `View`. Use it for padding, borders, or shadows. | |
| 81 | +| `onHeightChange` | `(height: number) => void` | — | Callback fired whenever a new height is committed. Great for analytics or debugging. | |
| 82 | +| `...WebViewProps` | — | — | All remaining props are forwarded to the underlying `react-native-webview`. | |
20 | 83 |
|
21 | | -const result = await multiply(3, 7); |
| 84 | +> [!NOTE] |
| 85 | +> 🧩 `scrollEnabled` defaults to `false` so sizing remains deterministic. Only enable it if the WebView should manage its own scroll. |
| 86 | +
|
| 87 | +## 🧠 How It Works |
| 88 | + |
| 89 | +- Injected bridge observes DOM mutations, layout changes, font loads, and viewport shifts. |
| 90 | +- Height calculations are debounced via `requestAnimationFrame` and a short idle timer to prevent resize storms. |
| 91 | +- Measurements arrive through `postMessage`, then `useAutoHeight` coalesces them into a single render per frame. |
| 92 | +- Package exports the bridge, hook, and helpers individually, making it easy to build bespoke wrappers when needed. |
| 93 | + |
| 94 | +## ⚖️ Performance Snapshot |
| 95 | + |
| 96 | +| Scenario | Plain `react-native-webview` | `react-native-sized-webview` | |
| 97 | +| --- | --- | --- | |
| 98 | +| Initial render layout shifts | Requires timers / manual height guesswork | Zero shifts; height resolved before paint | |
| 99 | +| React state updates on content change | Manual `postMessage` plumbing | Automatic bridge with RAF + debounce guard | |
| 100 | +| Scrolling in parent `ScrollView` | Nested scroll can fight gestures | Parent retains full momentum and gesture priority | |
| 101 | + |
| 102 | +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. |
| 103 | + |
| 104 | +## 🛠️ Local Development |
| 105 | + |
| 106 | +```sh |
| 107 | +yarn |
| 108 | +yarn lint |
| 109 | +yarn typecheck |
| 110 | +yarn test --watch=false |
| 111 | +yarn example ios # or yarn example android |
22 | 112 | ``` |
23 | 113 |
|
| 114 | +This project uses [react-native-builder-bob](https://github.com/callstack/react-native-builder-bob) for packaging and [release-it](https://github.com/release-it/release-it) for publishing. |
24 | 115 |
|
25 | | -## Contributing |
| 116 | +## 🤝 Contributing |
26 | 117 |
|
27 | 118 | - [Development workflow](CONTRIBUTING.md#development-workflow) |
28 | 119 | - [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request) |
29 | 120 | - [Code of conduct](CODE_OF_CONDUCT.md) |
30 | 121 |
|
31 | | -## License |
| 122 | +> [!CAUTION] |
| 123 | +> 🔬 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. |
| 124 | +
|
| 125 | +## 🧑💻 Maintainer |
32 | 126 |
|
33 | | -MIT |
| 127 | +- Mateus Andrade ([@mCodex](https://github.com/mCodex)) |
34 | 128 |
|
35 | | ---- |
| 129 | +## 📄 License |
36 | 130 |
|
37 | | -Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob) |
| 131 | +MIT © [Mateus Andrade](https://github.com/mCodex) |
0 commit comments