Quick Start
This page walks through a minimal working setup using a plain class with decorators and raw Locator accessors — the simplest entry point.
1. Define a page object
Section titled “1. Define a page object”import type { Locator, Page } from "@playwright/test";import { RootSelector, Selector, SelectorByRole } from "playwright-page-object";
@RootSelector("CheckoutPage")class CheckoutPage { constructor(readonly page: Page) {}
@Selector("PromoCodeInput") accessor PromoCodeInput!: Locator;
@SelectorByRole("button", { name: "Apply" }) accessor ApplyPromoButton!: Locator;
async applyPromoCode(code: string) { await this.PromoCodeInput.fill(code); await this.ApplyPromoButton.click(); }}The @RootSelector("CheckoutPage") scopes every child accessor under page.locator("body").getByTestId("CheckoutPage"). Each child accessor resolves lazily — the locator chain is rebuilt on every access, so the same accessor can be reused across awaits without staleness.
2. Use it in a test
Section titled “2. Use it in a test”import { test } from "@playwright/test";
test("apply promo code", async ({ page }) => { const checkout = new CheckoutPage(page); await checkout.applyPromoCode("SAVE20");});3. Optional: typed fixtures
Section titled “3. Optional: typed fixtures”For test suites that use Playwright fixtures, createFixtures wires up instantiation:
import { test as base } from "@playwright/test";import { createFixtures } from "playwright-page-object";
export const test = base.extend<{ checkoutPage: CheckoutPage }>( createFixtures({ checkoutPage: CheckoutPage }),);
test("apply promo code", async ({ checkoutPage }) => { await checkoutPage.applyPromoCode("SAVE20");});See the Fixtures guide for factory-function support and shared configuration.
What just happened
Section titled “What just happened”@RootSelector(id)set the class’s root locator topage.locator("body").getByTestId(id).@Selector(id)resolved each child accessor asroot.getByTestId(id).@SelectorByRole(...)resolved asroot.getByRole(...).- Locators were lazy — each
.fill()or.click()rebuilt the chain from the currentpage.
- Choosing a Style — when to use plain classes vs. fragments vs. built-in POM.
- Plain Classes guide — deeper coverage of this pattern.
- Decorator API — full reference for all decorators.