Working with WebView
1. Installing WebView
To use WebView in an Expo project, you need to install the @react-native-webview/webview package.
After installation, you must configure your project to use the WebView component. For Expo managed projects, you may need to run:
| Step | Description | Notes |
|---|---|---|
| 1 | Install the WebView package | Use npm install or expo install |
| 2 | Link the package (if needed) | For Expo Go, linking is handled automatically |
| 3 | Import WebView in your component | Use import { WebView } from 'react-native-webview' |
2. Creating WebView Component
Example: Basic WebView Component
import { WebView } from 'react-native-webview';
<WebView
source={{ uri: 'https://expo.dev' }}
style={{ flex: 1 }}
/>
| Property | Description | Default | Notes |
|---|---|---|---|
| source | URL or HTML content to display | null |
Required. Can be a URL string or object with uri property |
| style | Styling for the WebView component | {} |
Must include flex: 1 to fill container |
| javaScriptEnabled | Enables JavaScript execution | true |
Set to false for security in read-only content |
| scalesPageToFit | Enables page scaling | true |
Controls whether content scales to fit the screen |
Note: The WebView component requires proper styling to display content correctly. Always set
flex: 1 in the style prop to ensure it fills its container.
3. Loading URLs
| Property | Values | Description |
|---|---|---|
| source | { uri: 'https://example.com' } |
URL to load in the WebView |
| source | { html: '<html><body>Hello</body></html>' } |
HTML string to render |
Example: Loading a URL
import { WebView } from 'react-native-webview';
<WebView
source={{ uri: 'https://expo.dev' }}
style={{ flex: 1 }}
/>
Note: On iOS, you may need to add
NSAppTransportSecurity to your Info.plist for non-HTTPS URLs.
4. Loading HTML Content
Example: Loading Local HTML File
import { WebView } from 'expo-web-browser';
<WebView
source={{ uri: 'file:///android_asset/web/index.html' }}
style={{ flex: 1 }}
/>
| Property | Description | Values |
|---|---|---|
| source | HTML content to load | uri, html, or file |
| style | Styling for the WebView component | Object with standard style properties |
Note: On Android, assets must be placed in
android/app/src/main/assets.
5. Handling Navigation
Example: Basic WebView Navigation
import { WebView } from 'react-native-webview';
<WebView
source={{ uri: 'https://expo.dev' }}
onNavigationStateChange={(navState) => {
console.log('Current URL:', navState.url);
}}
/>
| Property | Description | Values |
|---|---|---|
| onNavigationStateChange | Callback when navigation state changes | function |
| navigationState | Current navigation state object | object |
Note: The
navigationState object includes properties like url, title, and canGoBack.
Example: Handling Back Navigation
import { WebView } from 'react-native-webview';
<WebView
source={{ uri: 'https://expo.dev' }}
onNavigationStateChange={(navState) => {
if (navState.canGoBack) {
console.log('Can go back');
}
}}
/>
6. Injecting JavaScript
Example: Injecting JavaScript into WebView
import { WebView } from 'react-native-webview';
const injectedJavaScript = `
const newTitle = 'Injected Title';
document.title = newTitle;
true; // required for injecting a script
`;
<WebView
source={{ uri: 'https://example.com' }}
injectedJavaScript={injectedJavaScript}
/>
| Property | Description | Values |
|---|---|---|
| injectedJavaScript | JavaScript code to inject into the WebView | string |
| injectedJavaScriptBeforeContentLoaded | JavaScript to inject before content is loaded | string |
Note: The injected JavaScript must return
true to indicate successful execution.
7. Communicating with Web Page
Expo WebView provides several mechanisms to communicate between the native app and the web page content. These include:
postMessagefrom web to nativeinjectJavaScriptfrom native to web
Example: Sending message from web to native
// In your web page
window.ReactNativeWebView.postMessage("Hello from web");
Example: Receiving message in native app
// In your React Native component
<WebView
source={{ uri: 'https://example.com' }}
onMessage={(event) => {
console.log("Received from web:", event.nativeEvent.data);
}}
/>
Example: Sending message from native to web
// In your React Native component
const injectJavaScript = `
window.myAppData = {
userId: '12345',
theme: 'dark'
};
true; // Required for injectJavaScript to work
`;
<WebView
source={{ uri: 'https://example.com' }}
injectedJavaScript={injectJavaScript}
/>
| Method | Description | Usage |
|---|---|---|
| onMessage | Callback for messages sent from web to native | onMessage={(event) => console.log(event.nativeEvent.data)} |
| postMessage | Method available in web context to send data to native | window.ReactNativeWebView.postMessage('data') |
| injectedJavaScript | JavaScript to inject into the web page before it loads | injectedJavaScript={jsCode} |
Note: The
postMessage method is only available in the web context when using Expo WebView. It's not a standard DOM API but an Expo-specific extension.
8. Handling Messages
Example: Receiving and Sending Messages
import React from 'react';
import { WebView } from 'react-native';
const WebViewExample = () => {
const [messages, setMessages] = React.useState([]);
const handleMessage = (event) => {
const message = event.nativeEvent.data;
setMessages(prev => [...prev, message]);
};
const sendMessageToWebView = () => {
const webViewRef = React.useRef();
webViewRef.current?.injectJavaScript('window.postMessage("Hello from React Native", ' + '"*")');
};
return (
<WebView
ref={webViewRef}
source={{ uri: 'https://example.com' }}
onMessage={handleMessage}
javaScriptEnabled={true}
/>
);
};
export default WebViewExample;
| Property | Description | Notes |
|---|---|---|
| onMessage | Callback function when a message is received from the WebView | Receives an event object with nativeEvent.data |
| injectJavaScript | Method to inject JavaScript into the WebView | Used to send messages from React Native to WebView |
Note: Messages are sent using
window.postMessage in the WebView and received via onMessage in React Native.
Warning: Ensure that the WebView's
javaScriptEnabled is set to true for message handling to work.
9. Managing WebView State
Example: Setting initial state in WebView
import { WebView } from 'react-native-webview';
const initialHtml = `
<html>
<head></head>
<body>
<div id="app"></div>
<script>
window.appState = {
user: { name: 'John Doe', isLoggedIn: true },
theme: 'dark'
};
</script>
</body>
</html>`;
<WebView
source={{ html: initialHtml }}
startInLoadingState={true}
/>
| Property | Description | Values |
|---|---|---|
| injectJavaScript | Injects JavaScript into the WebView after it loads | string |
| injectedJavaScript | JavaScript to inject when WebView loads (deprecated) | string |
| injectedJavaScriptBeforeContentLoaded | JavaScript to inject before content loads | string |
Note: Use
injectJavaScript for dynamic state updates after WebView loads.
Example: Updating WebView state with injectJavaScript
const updateAppState = (newState) => {
const script = `
window.appState = ${JSON.stringify(newState)};
console.log('WebView state updated:', window.appState);
`;
webViewRef.current.injectJavaScript(script);
};
// Usage
updateAppState({ user: { name: 'Jane Doe', isLoggedIn: true }, theme: 'light' });
State Management Best Practices
- Use
injectJavaScriptto update state after WebView loads - Pass initial state via
source={{ html: ... }} - Avoid frequent injections; batch updates when possible
- Use
postMessagefor communication between WebView and React Native
10. Configuring User Agent
| Property | Values | Description |
|---|---|---|
| userAgent | string |
Sets the user agent string for the WebView. Can be used to identify the app or modify browser behavior. |
| userAgentWithApplication | boolean |
When true, appends the application name and version to the default user agent string. |
Example: Setting Custom User Agent
import { WebView } from 'react-native-webview';
<WebView
source={{ uri: 'https://example.com' }}
userAgent="MyApp/1.0 (Custom User Agent)"
/>
Example: Using Application User Agent
import { WebView } from 'react-native-webview';
<WebView
source={{ uri: 'https://example.com' }}
userAgentWithApplication={true}
/>
11. Handling Loading States
Example: Basic WebView with Loading Indicators
import React, { useState } from 'react';
import { WebView } from 'react-native-webview';
const MyWebView = () => {
const [loading, setLoading] = useState(true);
return (
<WebView
source={{ uri: 'https://example.com' }}
startInLoadingState={true}
renderLoading={() => <div><span>Loading...</span></div>}
onLoadEnd={() => setLoading(false)}
/>
);
};
| Property | Description | Default |
|---|---|---|
| startInLoadingState | Whether to show the loading indicator before the WebView loads. | false |
| renderLoading | Custom component to render during loading. | null |
| onLoadEnd | Called when the WebView finishes loading or fails. | null |
Note: The
renderLoading prop is not supported on all platforms. On iOS, it's only available in React Native versions 0.63 and above.
12. Enabling DOM Storage
| Property | Values | Description |
|---|---|---|
| domStorageEnabled | true | false |
Enables or disables DOM storage. Defaults to false. |
Note: Enabling DOM storage allows the WebView to store data in local storage, which can be useful for caching or persisting state between sessions.