Answer
waitForSelector and waitForLoadState in Playwright
page.waitForSelector()
Waits for an element matching a CSS selector to appear in the DOM and be in a specific state.
TypeScript
// Wait for element to appear (default: 'visible')
await page.waitForSelector('.product-list');
// Wait for element to be visible
await page.waitForSelector('.success-banner', { state: 'visible' });
// Wait for element to be hidden/gone
await page.waitForSelector('.loading-spinner', { state: 'hidden' });
// Wait for element to be present in DOM (even if hidden)
await page.waitForSelector('#modal', { state: 'attached' });
// Wait for element to be removed from DOM
await page.waitForSelector('.temp-banner', { state: 'detached' });
// Custom timeout
await page.waitForSelector('.chart', { timeout: 15000 });
States:
| State | Meaning |
|---|---|
'visible' (default) | Element exists AND is visible |
'hidden' | Element is invisible or removed |
'attached' | Element exists in DOM (even hidden) |
'detached' | Element removed from DOM |
Modern Alternative — locator.waitFor()
TypeScript
// Preferred over page.waitForSelector()
await page.locator('.product-list').waitFor({ state: 'visible' });
await page.locator('.spinner').waitFor({ state: 'hidden' });
page.waitForLoadState()
Waits for the page to reach a specific load state after navigation.
TypeScript
// After navigation, wait for full load
await page.goto('/products');
await page.waitForLoadState('load'); // default
// Wait for DOMContentLoaded only (faster)
await page.waitForLoadState('domcontentloaded');
// Wait for no network activity (great for SPAs)
await page.waitForLoadState('networkidle');
Load States:
| State | Description |
|---|---|
'load' | All resources loaded (images, scripts, etc.) |
'domcontentloaded' | DOM parsed and ready |
'networkidle' | No network requests for 500ms |
When to Use Each
TypeScript
// Use waitForLoadState after goto()
await page.goto('/dashboard');
await page.waitForLoadState('networkidle'); // SPA hydrated
// Use waitForSelector for dynamic content
await page.getByRole('button', { name: 'Load More' }).click();
await page.waitForSelector('.new-items'); // Wait for new items
// Modern approach — prefer locator.waitFor()
const newItems = page.locator('.product-card');
await newItems.waitFor();
await expect(newItems).toHaveCount(20);
Note: In most cases, Playwright's auto-waiting makes
waitForSelectorunnecessary. Use it only when you need to wait for something before reading a value or making a conditional check.
