When you embed a webpage in an iframe, it often has a fixed size. This can hide how well your website adapts to different devices. By using a dynamic viewport, you can better showcase your website’s design across various screen sizes.
Using React
Here’s how to create a responsive iframe component in React.
Step 1: Create the Component
First, you will create a ResponsiveIframe
component. This component will take two properties:
src
: The URL of the website you want to show.viewportWidth
: The width of the viewport in pixels.
interface ResponsiveIframeProps {
src: string
viewportWidth: number
}
const ResponsiveIframe = ({ src, viewportWidth }: ResponsiveIframeProps) => {
return (
<iframe
src={src}
style={{
width: viewportWidth,
}}
/>
)
}
Step 2: Make the Iframe Responsive
To make the iframe responsive, you can use the CSS scale property. This means the iframe will adjust its size based on the container it is in. First, you need to reference the iframe using the useRef
hook.
const iframeRef = useRef<HTMLIFrameElement>(null)
return (
<iframe
ref={iframeRef}
src={src}
style={{
width: viewportWidth,
}}
/>
)
Step 3: Calculate the Scale
Now you will need to calculate the scale based on the width of the parent container. You will create a function called resize
that does this.
const resize = useCallback(() => {
const iframe = iframeRef.current
const wrapper = iframe?.parentElement
if (!iframe || !wrapper) return
const wrapperWidth = wrapper.offsetWidth
const iframeWidth = iframe.offsetWidth
const scale = wrapperWidth / iframeWidth
iframe.style.transform = `scale(${scale})`
const wrapperHeight = wrapper.offsetHeight
const height = wrapperHeight / scale
iframe.style.height = `${height}px`
}, [])
Step 4: Use the useEffect
Hook
You want the resize
function to run when the window resizes and when the component first renders. You can use the useEffect
hook for this.
useEffect(() => {
resize()
window.addEventListener('resize', resize)
return () => window.removeEventListener('resize', resize)
}, [resize])
Complete React Component Code
Here is the full code for the ResponsiveIframe
component:
interface ResponsiveIframeProps {
src: string
width: number
}
const ResponsiveIframe = ({ src, width }: ResponsiveIframeProps) => {
const iframeRef = useRef<HTMLIFrameElement>(null)
const resize = useCallback(() => {
const iframe = iframeRef.current
const wrapper = iframe?.parentElement
if (!iframe || !wrapper) return
const wrapperWidth = wrapper.offsetWidth
const iframeWidth = iframe.offsetWidth
const scale = wrapperWidth / iframeWidth
iframe.style.transform = `scale(${scale})`
const wrapperHeight = wrapper.offsetHeight
const height = wrapperHeight / scale
iframe.style.height = `${height}px`
}, [])
useEffect(() => {
resize()
window.addEventListener('resize', resize)
return () => window.removeEventListener('resize', resize)
}, [resize])
return (
<iframe
ref={iframeRef}
src={src}
style={{ width, transformOrigin: 'top left' }}
/>
)
}
Usage Example
To use the ResponsiveIframe
component, you can set different viewport widths based on buttons:
const [viewportWidth, setViewportWidth] = useState<number>(1220)
return (
<div>
<ResponsiveIframe src="https://baraa.app" width={viewportWidth} />
<div className="buttons">
<button onClick={() => setViewportWidth(375)}>Mobile</button>
<button onClick={() => setViewportWidth(768)}>Tablet</button>
<button onClick={() => setViewportWidth(1220)}>Desktop</button>
</div>
</div>
)
Using Vanilla JavaScript
If you prefer not to use React, you can create a dynamic iframe with plain JavaScript. Here’s how:
<div class="iframe-wrapper">
<iframe id="iframe" src="https://baraa.app"></iframe>
</div>
const iframe = document.getElementById('iframe')
const resize = () => {
const wrapper = iframe.parentElement
if (!wrapper) return
const wrapperWidth = wrapper.offsetWidth
const iframeWidth = iframe.offsetWidth
const scale = wrapperWidth / iframeWidth
iframe.style.transform = `scale(${scale})`
const wrapperHeight = wrapper.offsetHeight
const height = wrapperHeight / scale
iframe.style.height = `${height}px`
}
resize()
window.addEventListener('resize', resize)