There are two kinds of dropdowns. Native HTML <select> elements and custom dropdowns built with divs, lists, and JavaScript. They look the same to the user but require completely different automation approaches. Knowing which one you are dealing with is step one.
import { test, expect } from '@playwright/test';
test('select by visible text', async ({ page }) => {
await page.goto('/topics/dropdowns');
// Select by the visible label text
await page.getByLabel('Country').selectOption({ label: 'India' });
await expect(page.getByLabel('Country')).toHaveValue('IN');
});
test('select by value attribute', async ({ page }) => {
await page.goto('/topics/dropdowns');
// Select by the value attribute of the <option>
await page.getByLabel('Country').selectOption('IN');
await expect(page.getByLabel('Country')).toHaveValue('IN');
});
test('select by index', async ({ page }) => {
await page.goto('/topics/dropdowns');
// Select by option index (0-based)
await page.getByLabel('Country').selectOption({ index: 2 });
});
test('select multiple options', async ({ page }) => {
await page.goto('/topics/dropdowns');
// For <select multiple>
await page.getByLabel('Skills').selectOption(['javascript', 'typescript', 'python']);
// Verify all selected
const selected = await page.getByLabel('Skills').inputValue();
expect(selected).toBe('javascript');
});Most modern apps do not use native <select>. They build custom dropdowns with divs, buttons, and lists. React Select, Material UI Select, Ant Design Select -- these all look like dropdowns but are not <select> elements. selectOption() will not work on them. You need to click and select manually.
import { test, expect } from '@playwright/test';
test('custom dropdown -- click to open, click to select', async ({ page }) => {
await page.goto('/topics/dropdowns');
// Step 1: Click the dropdown trigger to open it
await page.getByRole('combobox', { name: 'State' }).click();
// Step 2: Wait for the dropdown list to appear
await expect(page.getByRole('listbox')).toBeVisible();
// Step 3: Click the desired option
await page.getByRole('option', { name: 'Maharashtra' }).click();
// Step 4: Verify the selection
await expect(page.getByRole('combobox', { name: 'State' })).toHaveText('Maharashtra');
});
test('searchable custom dropdown', async ({ page }) => {
await page.goto('/topics/dropdowns');
// Click to open
await page.getByRole('combobox', { name: 'City' }).click();
// Type to filter options
await page.getByRole('combobox', { name: 'City' }).fill('Mum');
// Wait for filtered results
await expect(page.getByRole('option')).toHaveCount(1);
// Select the filtered option
await page.getByRole('option', { name: 'Mumbai' }).click();
await expect(page.getByRole('combobox', { name: 'City' })).toHaveText('Mumbai');
});Right-click the dropdown in the browser and Inspect
If the element is <select> with <option> children -- it is native. Use selectOption()
If the element is a <div>, <button>, or <input> with role="combobox" -- it is custom. Use click + select
Check for role="listbox" on the dropdown list and role="option" on items
If the dropdown has a search/filter input, it is definitely custom
For custom dropdowns, always wait for the listbox to be visible before clicking an option. Some dropdowns have animation delays. Without the wait, your click might land before the dropdown fully opens.
Calling selectOption() on a non-<select> element will throw an error. If you see "Element is not a select element," you are dealing with a custom dropdown. Switch to the click-based approach.
Q: How do you handle different types of dropdowns in Playwright?
A: First, I inspect the DOM to check if it is a native <select> or a custom component. For native selects, I use selectOption() which can select by value, label, or index. For custom dropdowns (React Select, Material UI, etc.), I click the trigger to open the list, wait for the listbox to be visible, then click the desired option. For searchable dropdowns, I fill() the search text first, wait for filtered results, then click. I always verify the selected value after selection.
Key Point: Native <select> uses selectOption(). Custom dropdowns use click to open + click to select. Inspect the DOM to know which type you have. Always wait for the listbox before selecting.