Playwright: How to Wait Until Element Is Visible (Best Practices + Examples)
When automating UI interactions using Playwright, waiting for an element to become visible is a critical step to avoid flaky tests or runtime errors.
In this guide, youβll learn how to wait until an element is visible in Playwright using reliable methods, with code examples, a comparison table, and best practices.
β Quick Answer
await page.locator('#my-element').waitFor({ state: 'visible' });
This waits until the element:
- Exists in the DOM
- Is not hidden (
display: none,visibility: hidden, etc.) - Has non-zero dimensions
π¦ Method 1: locator.waitFor({ state: 'visible' }) (Recommended)
await page.locator('.loader').waitFor({ state: 'visible' });
- β Clean, readable
- β Retries automatically
- β Respects timeouts
π§ͺ Method 2: expect(locator).toBeVisible() (Built-in Assertion)
If you're using Playwright's test runner:
import { expect } from '@playwright/test';
await expect(page.locator('#login-button')).toBeVisible();
- β Assertion-style
- β Waits automatically
- β Great for test suites
π§ͺ Method 3: Manual Loop (Advanced)
await page.waitForFunction(() => {
const el = document.querySelector('#my-element');
return el && el.offsetParent !== null;
});
- π§ For complex visibility checks
- β οΈ More verbose and brittle
β± Optional: Set Timeout
await page.locator('.modal').waitFor({ state: 'visible', timeout: 10000 });
- π Waits up to 10 seconds
- Throws error if not visible in time
π§° Comparison Table
| Method | Type | Auto Retry | Timeout Support | Best For |
|---|---|---|---|---|
locator.waitFor({ state: 'visible' }) | Locator API | β Yes | β Yes | Simple, clean wait |
expect(locator).toBeVisible() | Assertion | β Yes | β Yes | Tests with built-in runner |
waitForFunction(...) | JS Eval | β No | β Yes | Complex custom visibility |
π§© Use Cases
| Scenario | Recommended Approach |
|---|---|
| Waiting for modal to appear | locator.waitFor({ state: 'visible' }) |
| Waiting for button before clicking | expect(locator).toBeVisible() |
| Waiting for element after AJAX load | locator.waitFor() |
| Waiting with custom DOM logic | page.waitForFunction() |
π§ Pro Tips
- Use
state: 'attached'if element may exist but be hidden - Chain with actions:
await page.locator('#menu').waitFor({ state: 'visible' });
await page.click('#menu');
- Use Playwright Testβs auto-waiting: it waits for visibility before
click(),fill(), etc.
β Common Mistakes
| Mistake | Fix |
|---|---|
| Waiting for hidden elements | Use state: 'visible', not just attached |
Not awaiting the waitFor call | Always use await before .waitFor() |
Using waitForSelector() (deprecated) | Use locator.waitFor() instead |
π Conclusion
To wait for an element to become visible in Playwright:
- Use
locator.waitFor({ state: 'visible' })for reliability - Use
expect(...).toBeVisible()in test assertions - Use custom logic with
waitForFunction()when needed
These strategies will make your tests more stable and your scripts more accurate.