</>

Technology

Playwright

Difficulty

Intermediate

Interview Question

A custom React dropdown is built with divs, not a native <select>. How do you handle it in Playwright?

Answer

Scenario: Handling a Custom React Dropdown

Modern React apps use custom dropdown components built with <div>, <ul>, <li> elements — not native <select>. These need a different approach.

Inspect the HTML Structure First

HTML
<!-- Typical custom dropdown HTML -->
<div class="dropdown" aria-expanded="false">
  <button class="dropdown-trigger" aria-haspopup="listbox">
    Select Country
  </button>
  <ul class="dropdown-list" role="listbox" hidden>
    <li role="option" data-value="US">United States</li>
    <li role="option" data-value="UK">United Kingdom</li>
    <li role="option" data-value="IN">India</li>
  </ul>
</div>

Strategy 1 — Click Trigger, Then Click Option (Most Common)

TypeScript
test('select from custom dropdown', async ({ page }) => {
  await page.goto('/register');

  // Step 1: Click the dropdown trigger to open it
  await page.getByRole('combobox', { name: 'Select Country' }).click();
  // OR
  await page.locator('.dropdown-trigger').click();

  // Step 2: Wait for options to appear
  await expect(page.getByRole('listbox')).toBeVisible();

  // Step 3: Click the desired option
  await page.getByRole('option', { name: 'United States' }).click();

  // Step 4: Verify selection
  await expect(page.getByRole('combobox')).toHaveText('United States');
});

Strategy 2 — Scope to the Dropdown Container

TypeScript
test('scoped dropdown selection', async ({ page }) => {
  // Get the specific dropdown container (important if multiple dropdowns on page)
  const countryDropdown = page.locator('[data-testid="country-select"]');

  // Open it
  await countryDropdown.click();

  // Select within the dropdown context
  await countryDropdown.getByText('India').click();

  await expect(countryDropdown).toContainText('India');
});

Strategy 3 — Material UI / Ant Design / React Select

TypeScript
// React Select (most popular)
test('React Select dropdown', async ({ page }) => {
  // The input inside React Select
  const selectInput = page.locator('.react-select__control');
  await selectInput.click();

  // Type to filter options
  await page.locator('.react-select__input input').fill('India');

  // Click the filtered option
  await page.locator('.react-select__option').filter({ hasText: 'India' }).click();

  // Verify
  await expect(page.locator('.react-select__single-value')).toHaveText('India');
});

// Ant Design Select
test('Ant Design Select', async ({ page }) => {
  await page.locator('.ant-select-selector').click();
  await page.locator('.ant-select-item-option').filter({ hasText: 'India' }).click();
  await expect(page.locator('.ant-select-selection-item')).toHaveText('India');
});

// MUI Select
test('Material UI Select', async ({ page }) => {
  await page.locator('#country-select').click();
  await page.getByRole('option', { name: 'India' }).click();
  await expect(page.locator('#country-select')).toHaveText('India');
});

Strategy 4 — Search/Autocomplete Dropdowns

TypeScript
test('autocomplete dropdown', async ({ page }) => {
  const input = page.getByPlaceholder('Search city...');

  // Type to trigger suggestions
  await input.fill('New Y');

  // Wait for suggestions to appear
  await expect(page.locator('.suggestions-dropdown')).toBeVisible();

  // Click desired suggestion
  await page.locator('.suggestion-item').filter({ hasText: 'New York' }).click();

  // Verify input shows selected value
  await expect(input).toHaveValue('New York');
});

Tips for Handling Custom Dropdowns

  1. Always check ARIA attributesrole="listbox", role="option", aria-expanded
  2. Use getByRole('option') for semantically correct selections
  3. Scope locators to the dropdown container when multiple exist
  4. Wait for options to appear before clicking
  5. Check data-testid attributes — often the most stable selector

Follow AutomateQA

Related Topics