Playwright: Interacting with Select Dropdown

Learn how to test select dropdown interactions in Playwright, including single select, multiple select, searchable options, defaults, and clearable values.
Ryan | Nov 01, 2026

Select dropdowns are common, but they are rarely all the same. Some allow one choice, some allow many, some filter as you type, and some include clear buttons or long scrollable lists. That is why dropdowns are a useful control to practice with in Playwright.

This guide uses the Codemo select dropdown playground to cover the main interaction patterns you are likely to automate: standard selection, multiple selection, defaults, long lists, searchable dropdowns, and clearable values.

Playground - General UI - Select Dropdown

Click here to practice select dropdown interactions in the Codemo Playground.

Why Test Select Dropdowns?

Dropdown tests help confirm that:

  • users can open the control and choose the expected option
  • selected values are shown correctly in the UI
  • default values are preserved on load
  • long lists remain usable
  • searchable dropdowns filter options correctly
  • clear buttons really reset the selection
  • multiple selection works correctly
Be careful when changing a select dropdown from single selection to multiple selection, as developers may mishandle string values versus arrays of values.

Basic Select Dropdown HTML

Before interacting with a select dropdown in Playwright, it's helpful to understand the underlying HTML structure. A basic select dropdown looks like this:

<label for="fruits">Choose a fruit:</label>
<select id="fruits" name="fruits">
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
</select>

Finding Dropdowns In Playwright

The most useful locators for this page are getByRole("combobox"), getByRole("option") to interact with the dropdown trigger and its options, and selectOption on the select element by label, value, or array of values.

The selectOption only works on the underlying <select> element
import { test, expect } from "@playwright/test"

test("selects an option from a dropdown", async ({ page }) => {
  await page.getByRole("combobox").first().click()
  await page.getByRole("option", { name: "Cherry" }).click()

  // Using selectOption by value, label, and array of values
  await page.getByLabel("Choose a fruit").selectOption("banana")
  await page.getByLabel("Choose a fruit").selectOption({ label: "Cherry" })
  await page.getByLabel("Choose a fruit").selectOption(["apple", "banana", "cherry"])
})
  • getByRole("combobox") for the dropdown trigger
  • getByRole("option", { name: "Banana" }) for the option list
  • selectOption on the select element by label, value, or array of values

Testing Standard Selection

The simplest scenario is selecting one option from a dropdown and checking that the selected value is correctly reflected in the UI.

In this test, I'm using the selected: true while asserting the option's selection state (an attribute that is usually set by aria-selected), to verify that the correct options are selected in the dropdown.
playground/select-dropdown.spec.ts
test("dropdown should register a standard selection", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/select-dropdown/")

  await page.getByRole("combobox", { name: "Choose an option" }).click()
  await page.getByRole("option", { name: "Banana" }).click()

  await expect(page.getByRole("option", { name: "Banana", selected: true })).toBeVisible()
  await expect(page.getByText("Selected: Banana")).toBeVisible()
})

Testing Multiple Selection

This test ensures that multiple selections are correctly registered and displayed in the UI.

playground/select-dropdown.spec.ts
test("dropdown should support multiple selections", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/select-dropdown/")

  await page.getByRole("combobox", { name: "Choose options" }).click()
  await page.getByRole("option", { name: "Red" }).click()
  await page.getByRole("option", { name: "Blue" }).click()

  await expect(page.getByRole("option", { name: "Red", selected: true })).toBeVisible()
  await expect(page.getByRole("option", { name: "Blue", selected: true })).toBeVisible()
  await expect(page.getByText("Selected: Red, Blue")).toBeVisible()
})

Testing Default Values

The default selection should be correctly reflected in the dropdown, validating that the initial value is properly set and displayed in the UI.

We should verify other options' selection states as well to ensure the default selection is correctly applied.
playground/select-dropdown.spec.ts
test("dropdown should keep its default selection", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/select-dropdown/")

  await page.getByRole("combobox", { name: "Default select" }).click()

  await expect(page.getByRole("option", { name: "Option 1 (Default)", selected: true })).toBeVisible()
  await expect(page.getByRole("option", { name: "Option 2", selected: false })).toBeVisible()
  await expect(page.getByRole("option", { name: "Option 3", selected: false })).toBeVisible()
  await expect(page.getByText("Default value: Option 1 (Default)")).toBeVisible()
})

Testing Long Lists

Long dropdown menus often reveal scrolling or rendering problems. This playground includes a 50-item list to simulate that case.

playground/select-dropdown.spec.ts
test("dropdown should handle a long list", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/select-dropdown/")

  await page.getByRole("combobox", { name: "Choose from many" }).click()
  await page.getByRole("option", { name: "Item 50" }).click()
  await expect(page.getByRole("combobox", { name: "Choose from many" })).toHaveText("Item 50")
  await expect(page.getByText("Selected: Item 50")).toBeVisible()
})

Testing Searchable Dropdowns

This is one of the most practical patterns because searchable dropdowns behave more like a combination of input and menu.

In this test, I'm using exact: true to ensure that the option selection is precise and not partially matched by other similar options.
playground/select-dropdown.spec.ts
test("dropdown should filter searchable options", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/select-dropdown/")

  await page.getByRole("button", { name: "Type to search" }).click()
  await page.getByPlaceholder("Search").fill("java")
  await page.getByRole("option", { name: "Java", exact: true }).click()

  await expect(page.getByRole("button", { name: "Java" })).toBeVisible()
  await expect(page.getByText("Selected: Java")).toBeVisible()
})

Testing Clearable Values

Clearable dropdowns allow users to remove their selection, which is an important interaction to test.

In this test, I'm finding the clear button using its class .clear-icon (. is the class selector prefix for classes in CSS selectors) and clicking it to remove the selected value.
playground/select-dropdown.spec.ts
test("dropdown should clear the selected value", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/select-dropdown/")

  await page.getByRole("button", { name: "Option A" })
    .locator(".clear-icon")
    .click()

  await expect(page.getByRole("button", { name: "Choose and clear" })).toBeVisible()
  await expect(page.getByText("Selected: (cleared)")).toBeVisible()
})

Practice With Codemo Playground

Codemo provides an interactive select dropdown playground where you can practice dropdown behavior one scenario at a time.

Try these challenges:

  1. Select Banana in the standard case and confirm the footer updates.
  2. Select Red and Blue in the multiple-select case.
  3. Verify that the default case loads with Option 1 (Default) already selected.
  4. Select Item 50 from the long-list case.
  5. Search for JavaScript in the searchable case.
  6. Select and then clear a value in the clearable case.

Complete Test Example

playground/select-dropdown.spec.ts
import { test, expect } from "@playwright/test"

test.describe("Playground - General UI - Select Dropdown", () => {
    test("dropdown should register a standard selection", async ({ page }) => {
        await page.goto("https://codemo.dev/playground/general/select-dropdown/")

        await page.getByRole("combobox", { name: "Choose an option" }).click()
        await page.getByRole("option", { name: "Banana" }).click()

        await expect(page.getByRole("option", { name: "Banana", selected: true })).toBeVisible()
        await expect(page.getByText("Selected: Banana")).toBeVisible()
    })

    test("dropdown should support multiple selections", async ({ page }) => {
        await page.goto("https://codemo.dev/playground/general/select-dropdown/")

        await page.getByRole("combobox", { name: "Choose options" }).click()
        await page.getByRole("option", { name: "Red" }).click()
        await page.getByRole("option", { name: "Blue" }).click()

        await expect(page.getByRole("option", { name: "Red", selected: true })).toBeVisible()
        await expect(page.getByRole("option", { name: "Blue", selected: true })).toBeVisible()
        await expect(page.getByText("Selected: Red, Blue")).toBeVisible()
    })

    test("dropdown should keep its default selection", async ({ page }) => {
        await page.goto("https://codemo.dev/playground/general/select-dropdown/")

        await page.getByRole("combobox", { name: "Default select" }).click()

        await expect(page.getByRole("option", { name: "Option 1 (Default)", selected: true })).toBeVisible()
        await expect(page.getByRole("option", { name: "Option 2", selected: false })).toBeVisible()
        await expect(page.getByRole("option", { name: "Option 3", selected: false })).toBeVisible()
        await expect(page.getByText("Default value: Option 1 (Default)")).toBeVisible()
    })

    test("dropdown should handle a long list", async ({ page }) => {
        await page.goto("https://codemo.dev/playground/general/select-dropdown/")

        await page.getByRole("combobox", { name: "Choose from many" }).click()
        await page.getByRole("option", { name: "Item 50" }).click()

        await expect(page.getByRole("combobox", { name: "Choose from many" })).toHaveText("Item 50")
        await expect(page.getByText("Selected: Item 50")).toBeVisible()

    })

    test("dropdown should filter searchable options", async ({ page }) => {
        await page.goto("https://codemo.dev/playground/general/select-dropdown/")

        await page.getByRole("button", { name: "Type to search" }).click()
        await page.getByPlaceholder("Search").fill("java")
        await page.getByRole("option", { name: "Java", exact: true }).click()

        await expect(page.getByRole("button", { name: "Java" })).toBeVisible()
        await expect(page.getByText("Selected: Java")).toBeVisible()
    })

    test("dropdown should clear the selected value", async ({ page }) => {
        await page.goto("https://codemo.dev/playground/general/select-dropdown/")

        await page.getByRole("button", { name: "Option A" }).locator(".clear-icon").click()

        await expect(page.getByRole("button", { name: "Choose and clear" })).toBeVisible()
        await expect(page.getByText("Selected: (cleared)")).toBeVisible()
    })
})

Source Code & Example Tests

Check out the source code and more example tests on GitHub.

Key Takeaways

  • Use getByRole("combobox") and getByRole("option") for most dropdown interactions.
  • Use selected: true to target the currently selected option in searchable dropdowns.
  • Use exact: true to ensure precise option selection in searchable dropdowns.
  • Use class selectors (e.g., .clear-icon) to interact with clear buttons in clearable dropdowns.
Practice dropdown selection, search, and clearing on the Codemo Playground and make your Playwright form tests more realistic.

References