Reputation: 8034
script:
<script>
function resizeIframe(obj) {
obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
}
</script>
html:
<iframe src="..." frameborder="0" scrolling="no" onload="resizeIframe(this)" />
There is a npm package react-iframe
, but it looks unfinished
(accepts only props url
, width
, height
):
The likely part of the solution is to listen to the load
event of
the iframe
, but in a way that is compatible with React.
Is there a way in React to set the height of an iframe
to the height of its scrollable contents?
my code:
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import Iframe from 'react-iframe'
export default class FullheightIframe extends Component {
componentDidMount() {
console.log("IFRAME DID MOUNT");
}
renderReactFrame() {
return (
<Iframe url="http://www.example.com" width="100%" height="100%" onLoad={()=>{console.log("IFRAME ON LOAD")}}></Iframe>
);
}
renderHTMLFrame() {
return (
<iframe
onLoad={(loadEvent)=>{
// NOT WORKING var frameBody = ReactDOM.findDOMNode(this).contentDocument.body; // contentDocument undefined
// NOT WORKING obj.nativeEvent.contentWindow.document.body.scrollHeight // contentWindow undefined
}}
ref="iframe"
src="http://www.example.com"
width="100%"
height="100%"
scrolling="no"
frameBorder="0"
/>
);
}
render() {
return (
<div style={{maxWidth:640, width:'100%', height:'100%', overflow:'auto'}}>
{this.renderHTMLFrame()}
</div>
);
}
}
Upvotes: 14
Views: 53259
Reputation: 19
Just use useState and useEffect with setTimeout with 100miliseconds and you are done
const [frameHeight , setFrameHeight] = useState()
useEffect(() => {
const frame = document.getElementById('myFrame');
console.log("height" , frame.contentWindow.document.body.scrollHeight + "px")
setTimeout(() => {
setFrameHeight(frame.contentWindow.document.body.scrollHeight + "px")
},100)
},[])
return (
<iframe srcdoc={content}
id="myFrame"
width="100%"
height={frameHeight}
frameBorder="0"
scrolling="no"
></iframe>
)
You'r Welcome !
Upvotes: 1
Reputation: 4016
The best and reliable way to fit iframe is to use
iframe-resizer package.
https://www.npmjs.com/package/iframe-resizer
Upvotes: 0
Reputation: 13077
This npm package will do what you what, it offers a range of different ways to calculate the height of the content in the iframe
https://www.npmjs.com/package/iframe-resizer-react
With this use case it can be configured as follows
<IframeResizer
heightCalculationMethod="bodyScroll"
src="http://anotherdomain.com/iframe.html"
/>
Upvotes: 2
Reputation: 1671
What you want to do is in your componentDidMount, run the script to set the height. [If you are loading external content, you might want to add event listener on the IFrame to wait until the external content is loaded.]
componentDidMount() {
const obj = ReactDOM.findDOMNode(this);
obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
}
There is another, more "reacty" way of doing this - where you would store the height in state.
componentDidMount() {
const obj = ReactDOM.findDOMNode(this);
this.setState({iFrameHeight: obj.contentWindow.document.body.scrollHeight + 'px'});
}
and then in your render:
render() {
return (
<div style={{maxWidth:640, width:'100%', height:this.state.iFrameHeight, overflow:'auto'}}>
{this.renderHTMLFrame()}
</div>
);
}
Upvotes: 4
Reputation: 131
A couple of things to note here:
componentDidMount()
you run the risk of the content not being present yet.class WrappedFrame extends React.Component {
state = { contentHeight: 100 };
handleResize = () => {
const { body, documentElement } = this.container.contentWindow.document;
const contentHeight = Math.max(
body.clientHeight,
body.offsetHeight,
body.scrollHeight,
documentElement.clientHeight,
documentElement.offsetHeight,
documentElement.scrollHeight
);
if (contentHeight !== this.state.contentHeight) this.setState({ contentHeight });
};
onLoad = () => {
this.container.contentWindow.addEventListener('resize', this.handleResize);
this.handleResize();
}
componentWillUnmount() {
this.container.contentWindow.removeEventListener('resize', this.handleResize);
}
render() {
const { contentHeight } = this.state;
return (
<iframe
frameBorder="0"
onLoad={this.onLoad}
ref={(container) => { this.container = container; }}
scrolling="no"
src="your.source"
style={{ width: '100%', height: `${contentHeight}px` }}
title="Some Content"
/>
);
}
}
In this example we're storing the determined content height in the component's state and using that state to set the height of the rendered iframe. Also, by putting the onLoad()
handler definition in the component, you save a tiny bit of performance in render()
by not creating a new handler function on every re-render.
Upvotes: 8
Reputation: 11430
None of the answers proposed so far worked for me. The hackish approach of doing a short setTimeout
from within onLoad
kind-of seems to do the job, at least in my case.
class SmartIFrame extends React.Component {
render() {
return <iframe srcDoc={this.props.srcDoc}
scrolling="no"
frameBorder={0}
width="100%"
onLoad = {e => setTimeout(() => {
const obj = ReactDOM.findDOMNode(this);
obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
}, 50)}/>
}
}
Upvotes: 1
Reputation: 8034
Here is the answer, but first two important things.
render()
methodonLoad
event (once the iframe if fully loaded)Here is the full code:
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
export default class FullheightIframe extends Component {
constructor() {
super();
this.state = {
iFrameHeight: '0px'
}
}
render() {
return (
<iframe
style={{maxWidth:640, width:'100%', height:this.state.iFrameHeight, overflow:'visible'}}
onLoad={() => {
const obj = ReactDOM.findDOMNode(this);
this.setState({
"iFrameHeight": obj.contentWindow.document.body.scrollHeight + 'px'
});
}}
ref="iframe"
src="http://www.example.com"
width="100%"
height={this.state.iFrameHeight}
scrolling="no"
frameBorder="0"
/>
);
}
}
Upvotes: 12