21
votes

Hi I know it's a known issue about the auto height of webview in react native, and I have tried all the possibles solutions I've found on the internet such as :

https://gist.github.com/epeli/10c77c1710dd137a1335

https://github.com/danrigsby/react-native-web-container/blob/master/index.js

and all the solutions suggested in: React native: Is it possible to have the height of a html content in a webview?

But unfortunately none of these seems to work for me, I understand that the workaround they all suggest is to set the title to the height, but in my case it seems that the title always stays the same which is : "text/html ...." and the rest of my html. I get the html content from an API, it comes without a body, head or html tags, I've also tried adding these tags manually to the html and nothing seems to work.

I would love to hear if anyone else had that problem and how did it get fixed.

11
I have same problem, I added javaScriptEnabled={true} and javaScriptEnabledAndroid={true} in my webview but in fist time load webview it will return "text/html..." and then webview will working with exactly height. I don't know fix it. Can you give me your solution?Hoa.Tran

11 Answers

23
votes

I wrap WebView inside a View, and set the height from the View.

<View style={{ height: 200 }}>
  <WebView
    automaticallyAdjustContentInsets={false}
    source={{uri: 'https://player.vimeo.com/video/24156534?title=0&byline=0&portrait=0'}}
  />
</View>
14
votes

I just follow this guide: https://github.com/react-native-community/react-native-webview/blob/master/docs/Guide.md#communicating-between-js-and-native and succeeded in my work. Here is solution: 1. Define script to send document height to native env after loaded website. 2. Handle onMesssage of webview component and reset Height via state.

const webViewScript = `
  setTimeout(function() { 
    window.postMessage(document.documentElement.scrollHeight); 
  }, 500);
  true; // note: this is required, or you'll sometimes get silent failures
`;


...
constructor(props) {
    super(props);
    this.state = {
      webheight:100,
    }

...

<WebView style={{height: this.state.webheight}}
  automaticallyAdjustContentInsets={false}
  scrollEnabled={false}
  source={{uri: "http://<your url>"}}
  onMessage={event => {
    this.setState({webheight: parseInt(event.nativeEvent.data)});
  }}
  javaScriptEnabled={true}
  injectedJavaScript ={webViewScript}
  domStorageEnabled={true}
></WebView>

Hope that help!

7
votes

A reliable implementation of this behavior is with useAutoheight hook from @formidable-webview/webshell library. The latter allows to inject "features" into WebViews, e.g. scripts and behaviors. In this example, we will use 3 features + the aforementioned hook:

  • HandleHTMLDimensionsFeature which is required by useAutoheight hook to get document size updates;
  • ForceResponsiveViewportFeature to work around mobile virtual viewport;
  • ForceElementSizeFeature to work around cyclic size constraints

This component should work with any webpage.

import React from 'react';
import makeWebshell, {
  HandleHTMLDimensionsFeature,
  ForceResponsiveViewportFeature,
  ForceElementSizeFeature,
  useAutoheight
} from '@formidable-webview/webshell';
import WebView from 'react-native-webview';

const Webshell = makeWebshell(
  WebView,
  new HandleHTMLDimensionsFeature(),
  new ForceResponsiveViewportFeature({ maxScale: 1 }),
  new ForceElementSizeFeature({
    target: 'body',
    heightValue: 'auto',
    widthValue: 'auto'
  })
);

export default function ResilientAutoheightWebView(props) {
  const { autoheightWebshellProps } = useAutoheight({
    webshellProps: props
  });
  return <Webshell {...autoheightWebshellProps} />;
}

More resources:

2
votes

The WebView has default styles. If you want to set height, you also need to add flex: 0, as stated in the documentation:

Please note that there are default styles (example: you need to add flex: 0 to the style if you want to use height property).

2
votes

I recommend react-native-autoheight-webview. it perfect work for me. https://github.com/iou90/react-native-autoheight-webview

2
votes

I waste whole day to fix the height issue but in the end I had to shift to another library This one is easy and good

https://github.com/archriss/react-native-render-html

2
votes

Using postMessage and onMessage like below worked for me perfectly. Credit to iamdhj

 onWebViewMessage = (event: WebViewMessageEvent) => {
    this.setState({webViewHeight: Number(event.nativeEvent.data)})
  }

  render() {
    return (
      <ScrollView>
        <WebView
          style={{ height: this.state.webViewHeight }}
          source={{html: '...'}}
          onMessage={this.onWebViewMessage}
          injectedJavaScript='window.ReactNativeWebView.postMessage(document.body.scrollHeight)'
        />
      </ScrollView>
    )
  }
1
votes

Apparently the problem was I had javaScriptEnabled={false}.

After enabling it everything worked.

1
votes

I made a little component to make this functionality reusable if it helps anyone!

import React, { useState } from "react";
import WebView from "react-native-webview";

const DynamicHeightWebView = (props) => {
  const [height, setHeight] = useState(0);
  const webViewScript = `
    setTimeout(function() { 
      window.ReactNativeWebView.postMessage(document.documentElement.scrollHeight); 
    }, 500);
    true; // note: this is required, or you'll sometimes get silent failures
  `;
  return <WebView
    {...props}
    style={{
      ...props.style,
      height: height,
    }}
    automaticallyAdjustContentInsets={false}
    scrollEnabled={false}
    onMessage={event => {
      setHeight(parseInt(event.nativeEvent.data));
    }}
    javaScriptEnabled={true}
    injectedJavaScript ={webViewScript}
    domStorageEnabled={true}
    useWebKit={true}
  />
}

export default DynamicHeightWebView;
0
votes

use package react-native-autoheight-webview

0
votes

You can get the content height by injecting the JS code as suggested by @ken-ratanachai-s. Although, You will experience certain irregularities in some devices (Extra height after the content). This is becuase the javascript returns the content height in pixels, but we need to use display points in react native. To fix this, Divide the height from javascript with the pixel ratio as follows.

import { WebView, PixelRatio } from 'react-native'

const [webviewHeight, setWebviewHeight] = useState(0)

const onProductDetailsWebViewMessage = event => {
    setWebviewHeight(Number(event.nativeEvent.data)/PixelRatio.get())
}

return <WebView
    originWhitelist={['*']}
    style={{ height: productDetailsWebviewHeight }}
    onMessage={onProductDetailsWebViewMessage}
    injectedJavaScript='window.ReactNativeWebView.postMessage(document.body.scrollHeight)'
    source={{ html: "..." }}
/>

Pixel ratio ref.: https://reactnative.dev/docs/pixelratio

Courtesy: https://stackoverflow.com/a/65976827/5321660