</>

Technology

Playwright

Difficulty

Beginner

Interview Question

How do you work with iframes in Playwright?

Answer

Handling iframes in Playwright

Playwright uses frameLocator() to interact with elements inside an <iframe>. This is much simpler than Selenium's switchTo().frame() approach.

Basic iframe Access

TypeScript
// Access an iframe by CSS selector
const iframe = page.frameLocator('iframe#payment-frame');

// Now use normal locators inside the iframe
await iframe.getByLabel('Card Number').fill('4111111111111111');
await iframe.getByLabel('Expiry').fill('12/26');
await iframe.getByRole('button', { name: 'Pay' }).click();

Access by iframe Name or Title

TypeScript
// By name attribute: <iframe name="checkout">
const iframe = page.frameLocator('[name="checkout"]');

// By src URL pattern
const iframe = page.frameLocator('iframe[src*="stripe.com"]');

Nested iframes

TypeScript
// Outer iframe
const outerFrame = page.frameLocator('#outer-iframe');

// Inner iframe inside the outer one
const innerFrame = outerFrame.frameLocator('#inner-iframe');

await innerFrame.getByRole('button', { name: 'Submit' }).click();

Using locator().contentFrame() (Playwright v1.43+)

TypeScript
const frameLocator = page.locator('iframe').contentFrame();
await frameLocator.getByLabel('Email').fill('test@example.com');

Wait for iframe to Load

TypeScript
// Wait for the iframe itself to appear
await page.locator('iframe#payment-frame').waitFor();

// Then access it
const iframe = page.frameLocator('iframe#payment-frame');
await iframe.getByLabel('Card number').fill('4111111111111111');

Full Example — Stripe Payment iframe

TypeScript
import { test, expect } from '@playwright/test';

test('complete payment with iframe', async ({ page }) => {
  await page.goto('/checkout');

  await page.getByRole('button', { name: 'Proceed to Payment' }).click();

  // Wait for Stripe iframe to appear
  await page.locator('iframe[src*="stripe.com"]').waitFor();

  const stripe = page.frameLocator('iframe[src*="stripe.com"]');
  await stripe.getByPlaceholder('Card number').fill('4242424242424242');
  await stripe.getByPlaceholder('MM / YY').fill('12/25');
  await stripe.getByPlaceholder('CVC').fill('123');

  await page.getByRole('button', { name: 'Pay Now' }).click();
  await expect(page).toHaveURL('/order-confirmed');
});

Key Difference from Selenium: No switchTo().frame() / switchTo().defaultContent() juggling. Playwright's frameLocator() returns scoped locators that automatically interact inside the frame.

Follow AutomateQA

Related Topics