Untangling React Native WebView
Turns out that React Native’s WebView has some challenges.

Motivation
Recently was working with a colleague who was struggling with one of the React Native charting libraries. One idea that we came up with is, why not use React Native’s WebView with a local HTML application (and our go-to web charting library).
note: In the end, we did not end up using this approach; but thought it important to capture some of the challenges we encountered.
Prerequisites
The examples are developed as a React Native (Expo) application written in TypeScript. So, if you are looking to follow along, you will need to setup your environment as described in Unofficial React Native TypeScript. At the same time, all of this equally applies to JavaScript implementations.
A Sidebar
While the Expo documentation on WebViews makes no mention of it, React Native is looking to eventually remove the WebView component from the core.
Warning Please use the react-native-community/react-native-webview fork of this component instead. To reduce the surface area of React Native, <WebView/> is going to be removed from the React Native core. For more information, please read The Slimmening proposal.
— React Native — WebView
Will cross that bridge at that time.
Hello World
note: The final example from this article is available for download.
Following the Expo documentation, we begin with the simplest of WebViews in a file src/components/MyInlineWeb/index.tsx:
Observations:
- The documentation indicates that for locally served HTML we need to set the originWhitelist property as shown
We use the MyInlineWeb component in App; src/App.tsx as follows:
...
import MyInlineWeb from './components/MyInlineWeb';export default class App extends React.Component {
public render() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<MyInlineWeb />
</View>
);
}
}
...
With the result of:

Observations:
- With this change, the application’s output is unexpected; the Text component is pushed to the top of the screen and the HTML content is not visible
Through a bit of trial and error, it appears that:
- The WebView does not have a fixed height and its style property does not support height; rather it automatically flex grows to fill the available vertical space. This explains why the Text component is pushed to the top of the screen
- The WebView appears to have a default width of 0; however, its style property does support width. This explains why the HTML content is not visible
A quick fix is to set the secondary-axis alignment (a flexbox thing) to stretch; updating src/App.tsx:
...
const styles = StyleSheet.create({
container: {
alignItems: 'stretch',
...
},
});
With the result of:

Observations:
- With this change, the HTML is visible; although it seems unusually small. This, however, is somewhat expected we did not set the HTML5 viewport meta tag
Hello World Revisited
Instead of defining the HTML inline, we will use a local HTML file instead, e.g., src/components/MyInlineWeb/html/index.html:
Observations:
- We use the viewport tag to set the initial scale and disable zooming
We update the MyInlineWeb component to use this HTML file; updating src/components/MyInlineWeb/index.tsx:
...
import html from './html/index.html';export default class MyInlineWeb extends Component {
public render() {
return <WebView originWhitelist={['*']} source={html} />;
}
}
In order for TypeScript to support importing HTML files, we need to create a type declaration file; src/types/html.d.ts:
Observation:
- While unusual, HTML files are imported as numeric identifiers
With the result of:

Hello World Revisited with JavaScript
Having HTML without JavaScript is not terribly interesting; so we create src/components/MyInlineWeb/html/main.js:
and use it in src/components/MyInlineWeb/html/index.html:
...
<html>
...
<body>
...
<script src="main.js"></script>
</body>
</html>
With a result of:

Hello World Revisited with JavaScript and Message Passing
Finally, having HTML with JavaScript without being able to interact with the React Native application is not very interesting.
So… We update our React Native code with two buttons, yellow and red, that when pressed sends a message to the HTML application; the HTML application changes the background color based on the content of the message.

We first need to update the HTML application’s JavaScript to listen for messages; src/components/MyInlineWeb/html/main.js:
We then update the MyInlineWeb component to send a message to the HTML application based on changes to it’s color property; src/components/MyInlineWeb/index.tsx:
Finally we update the App component with the buttons and the supporting code to update the color property on the MyInlineWeb component; src/App.tsx:
Failure to Pass Messages Back
Both the Expo and React Native documentation indicate that there is a mechanism for the HTML application to pass messages back to the React Native application; the onMessage property and window.postMessage method.
Spent a fair amount of time exploring this using the iOS simulator and could not get this feature to work; basically the React Native application would essentially crash when postMessage was called.
Decided to give up exploring this in this article when I found a recent article entitled, Fixing React Native WebView’s postMessage for iOS.
Wrap Up
While using React Native’s WebView is not an ideal solution; it is handy to know that we can use it to get us out of a jam if needed.