Create Dynamic Viewports with Iframes

April 5, 2024

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)

Get Updates

Join my newsletter to keep up with my latest projects, articles, and the cool stuff i find online.