Playwright: Interacting with Checkbox

Learn how to test checkbox interactions in Playwright, including multiple selection, defaults, disabled states, and stored values.
Ryan | Oct 25, 2026

Checkboxes are one of the simplest form controls, but they exercise a different testing pattern than radio buttons. A radio group accepts one choice at a time. Checkboxes let users opt into multiple independent values, which makes them common in filters, permissions, preferences, and multi-select forms.

This guide uses the Codemo checkboxes playground to walk through the main scenarios you should automate: standard checks, default state, disabled checkboxes, and stored value verification.

Playground - General UI - Checkbox

Click here to practice checkbox interactions in the Codemo Playground.

Why Test Checkboxes?

Checkbox tests help you verify that:

  • users can select more than one option at a time
  • toggling one box does not unexpectedly affect another
  • default checked states are preserved on load
  • disabled checkboxes remain unchanged
  • the application stores the correct internal values

Basic Checkbox HTML

Before we test checkboxes, let's understand what a checkbox element looks like in HTML:

index.html
<input type="checkbox" id="option1" name="options" value="1" />
<label for="option1">Option 1</label>

<input type="checkbox" id="option2" name="options" value="2" />
<label for="option2">Option 2</label>

A checkbox input element can have attributes like:

  • type: Should be checkbox for checkboxes
  • id: Unique identifier for the input
  • name: Groups checkboxes together (optional)
  • value: The value submitted when the checkbox is selected
  • disabled: Makes the checkbox non-selectable
  • aria-checked: Indicates the current checked state of the checkbox (true or false)

Testing Standard Checks

The first case verifies that multiple checkboxes can be toggled independently.

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

  const caseCard = page.getByTestId("playground-case-standard-checks")

  await caseCard.getByLabel("Option 1").check()
  await caseCard.getByLabel("Option 2").check()
  await caseCard.getByLabel("Option 3").check()

  await caseCard.getByLabel("Option 2").uncheck()

  await expect(caseCard).toContainText("Selected: 2")
})

This is the main difference from radio button testing: a second selection should not clear the first one.

Testing Default Checked State

Some forms ship with a recommended or pre-approved option already selected. That state should be validated explicitly.

playground/checkboxes.spec.ts
test("checkboxes should keep the default option checked", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/checkboxes/")

  const caseCard = page.getByTestId("playground-case-default-check")

  await expect(caseCard.getByLabel("Option 1 (Default)")).toBeChecked()
  await expect(caseCard).toContainText("Option 1 checked: Yes")
  await expect(caseCard.getByLabel("Option 2")).not.toBeChecked()
  await expect(caseCard.getByLabel("Option 3")).not.toBeChecked()
})

Testing Disabled State

Disabled checkboxes should not allow any interaction, even if one of them is already checked.

playground/checkboxes.spec.ts
test("disabled checkboxes should stay unchanged", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/checkboxes/")

  const caseCard = page.getByTestId("playground-case-disabled-state")

  await expect(caseCard.getByLabel("Option 2 (Checked, Disabled)")).toBeDisabled()
  await expect(caseCard.getByLabel("Option 2 (Checked, Disabled)")).toBeChecked()
  await expect(caseCard).toContainText("Option 2 state: Checked")
})

Testing Stored Values

The value-check case is useful because the visible labels are not the only thing that matters. The checkbox group stores the internal values from the items array, such as banana, apple, and cherry.

playground/checkboxes.spec.ts
test("checkboxes should store internal values", async ({ page }) => {
  await page.goto("https://codemo.dev/playground/general/checkboxes/")

  const caseCard = page.getByTestId("playground-case-value-check")

  await caseCard.getByLabel("Banana").check()
  await caseCard.getByLabel("Cherry").check()

  await expect(page.getByTestId("playground-case-footer-value-check")).toHaveText(
    "Selected: banana, cherry",
  )
})
When checkbox labels differ from submitted values, assert the stored values somewhere in the UI or network behavior so the test covers the real business input.

Practice With Codemo Playground

Codemo provides an interactive checkboxes playground where you can test multi-select behavior one case at a time.

Try these challenges:

  1. Check Option 1 and Option 2 together and verify both remain selected.
  2. Confirm the default case loads with Option 1 already checked.
  3. Verify that the disabled case keeps Option 2 checked and unchanged.
  4. Select Banana and Cherry in the value case and confirm the footer shows stored values.

Complete Test Example

playground/checkboxes.spec.ts
import { test, expect } from "@playwright/test"

test.describe("Playground - General UI - Checkboxes", () => {
  test("checkboxes should support multiple selections", async ({ page }) => {
    await page.goto("https://codemo.dev/playground/general/checkboxes/")

    const caseCard = page.getByTestId("playground-case-standard-checks")

    await caseCard.getByLabel("Option 1").check()
    await caseCard.getByLabel("Option 2").check()
    await caseCard.getByLabel("Option 3").check()

    await caseCard.getByLabel("Option 2").uncheck()

    await expect(caseCard).toContainText("Selected: 2")
  })

  test("checkboxes should keep the default option checked", async ({ page }) => {
    await page.goto("https://codemo.dev/playground/general/checkboxes/")

    const caseCard = page.getByTestId("playground-case-default-check")

    await expect(caseCard.getByLabel("Option 1 (Default)")).toBeChecked()
    await expect(caseCard).toContainText("Option 1 checked: Yes")
    await expect(caseCard.getByLabel("Option 2")).not.toBeChecked()
    await expect(caseCard.getByLabel("Option 3")).not.toBeChecked()
  })

  test("disabled checkboxes should stay unchanged", async ({ page }) => {
    await page.goto("https://codemo.dev/playground/general/checkboxes/")

    const caseCard = page.getByTestId("playground-case-disabled-state")

    await expect(caseCard.getByLabel("Option 2 (Checked, Disabled)")).toBeDisabled()
    await expect(caseCard.getByLabel("Option 2 (Checked, Disabled)")).toBeChecked()
    await expect(caseCard).toContainText("Option 2 state: Checked")
  })

  test("checkboxes should store internal values", async ({ page }) => {
    await page.goto("https://codemo.dev/playground/general/checkboxes/")

    const caseCard = page.getByTestId("playground-case-value-check")

    await caseCard.getByLabel("Banana").check()
    await caseCard.getByLabel("Cherry").check()

    await expect(page.getByTestId("playground-case-footer-value-check")).toHaveText(
      "Selected: banana, cherry",
    )
  })
})

Source Code & Example Tests

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

Key Takeaways

  • Use getByLabel() or getByRole("checkbox") for stable checkbox locators.
  • Assert that multiple selections can coexist when the UI is designed for it.
  • Validate default and disabled states explicitly.
  • Check internal stored values when labels and values are different.

References

Practice checkbox toggling, defaults, and stored values on the Codemo Playground and make your multi-select tests more dependable.