What does the >> token do inside a Playwright selector string like css=article >> text=Reopen?
answer
- Parts are queried one inside the next
- Like nested querySelector calls
- The last part wins by default
- A leading star changes the result
- Quote the body to escape the token
basics
~20 sThe >> token chains selector parts: each part is queried relative to the previous part's result, like nested querySelector calls. Prefixing a part with an asterisk captures that intermediate element instead of the last one.
solid answer
~40 s`>>` joins selector parts into a chain, and each part is queried **relative to the element the previous part matched** -- `css=article >> css=.footer >> text=Reopen` is equivalent to nested `querySelector` calls. Engines can be mixed across parts, which is the point: it lets a text lookup be scoped by a structural CSS selector. By default the chain resolves to the **last** part's match; prefixing a part with `*`, as in `*css=article >> text=Reopen`, makes the chain resolve to that part instead, giving you the container rather than the contained element. Only one part may capture. A body that genuinely contains `>>` must be quoted, as in `text="deploy >> rollback"`. Playwright's own documentation recommends chaining locators in code instead, since a mistyped method is a compile error while a mistyped string is a timeout.
code
typescript · 8 lines// Each part is queried inside the previous match, engines may be mixed.
await page.locator('css=article.issue-card >> css=.footer >> text=Reopen').click();
// The * prefix captures the card instead of the element holding the text.
await page.locator('*css=article.issue-card >> text=Reopen').click();
// A body containing >> must be quoted or the chain splits at it.
await page.locator('text="deploy >> rollback"').click();go deeper
Read >> as nesting: each part searches inside what the previous part found, and the result is the last part's match. You will meet the syntax in generated selectors more often than you will write it.
Explain the relative-query semantics and the asterisk capture, and know that a body containing >> must be quoted. Be able to convert a chained string into the equivalent nested queries out loud.
In review, push chained strings towards locator chaining in code, because the failure mode changes from a silent timeout to a compile error and each intermediate step becomes nameable and traceable.
Decide whether selector strings are a public interface in your test tooling. Helpers that take a single selector parameter keep >> alive; designing them around locators instead removes a whole syntax from the team's vocabulary.
## How a chained selector resolves A selector string may hold several parts joined by the `>>` token. Each part names an engine -- either explicitly or by inference -- and **each part is queried relative to the element the previous part matched**. So ```txt css=article >> css=.footer > .actions >> css=button[type=submit] ``` behaves like ```javascript document.querySelector('article') .querySelector('.footer > .actions') .querySelector('button[type=submit]'); ``` Engines can be mixed freely across parts, which is the point of the syntax: `css=article.issue-card >> text=Reopen` scopes a text lookup to a card without expressing "text content" in CSS. By default the chain **resolves to whatever the last part matched**. The earlier parts exist only to narrow the search root. ## Capturing an intermediate part with `*` Prefix one part with `*` and the chain resolves to *that* part's element instead of the last one: - `css=article >> text=Reopen` resolves to the element holding the text. - `*css=article >> text=Reopen` resolves to the **article** that contains an element with that text. This is the raw-selector way of saying "the container that has this inside it". Only one part may carry the `*`; a second one raises an invalid-selector error saying that only one selector can capture using the `*` modifier. ## Escaping a literal `>>` The token is found by scanning for `>>` outside quoted regions, so a body that genuinely contains the characters must be quoted: ```txt text="deploy >> rollback" ``` Without the quotes the string splits into `text=deploy` and `rollback`, and the second part is inferred as a CSS type selector for a `<rollback>` element -- a confusing failure, because both halves are individually valid. ## Why locator chaining is now the recommendation Playwright's documentation recommends chaining locators in preference to `>>`, and recommends filtering by another locator in preference to the `*` capture. The reasons are mechanical rather than stylistic: 1. Locator chaining is expressed in code, so a typo in a method name is a compile error while a typo inside a selector string is a runtime timeout. 2. An intermediate locator can be named, reused and logged, whereas an intermediate part of a selector string is anonymous. 3. Trace and error output reads better when each step is a distinct locator. | | `>>` chaining | Locator chaining in code | |---|---|---| | Where it lives | one string | successive calls | | Mixing engines | free | free | | Capturing a container | `*` prefix on a part | a filter by a child locator | | Failure mode | runtime invalid selector or timeout | usually a type error | ## When the string form still earns its place - A selector produced by a tool or read from configuration arrives as one string, and `>>` keeps it one string. - Test-scaffolding helpers that accept a single `selector: string` parameter can express a scoped lookup without inventing their own composition API. - Reading generated or recorded selectors is easier if you can parse the syntax at sight. ## In an issue tracker `page.locator('css=article.issue-card >> css=.footer >> text=Reopen')` clicks the Reopen control inside a card's footer, mixing a structural CSS scope with a text lookup. Move the `*` to the front -- `page.locator('*css=article.issue-card >> text=Reopen')` -- and the same chain hands you the card itself, which is what you want if the next step is asserting on the card's title or status chip.
- Can more than one part of a chained selector carry the * capture prefix?No. A chain resolves to exactly one element set, so only one part may capture. Adding a second `*` raises an invalid-selector error stating that only one of the selectors can capture using the `*` modifier, and it is raised at parse time rather than surfacing as a timeout.
- Why does Playwright's documentation prefer locator chaining over the >> token?Because the composition moves from a string into code. Successive locator calls are checked by the compiler, each intermediate can be named and reused, and errors and traces show a distinct step per locator. A `>>` string is opaque: a typo inside it becomes a runtime timeout rather than a compile-time failure.
- What happens if a text body contains >> and you do not quote it?The scanner splits on the token because it only ignores `>>` inside quoted regions, so `text=deploy >> rollback` becomes two parts: a text lookup for `deploy` and a CSS type selector for a `<rollback>` element. Both halves are individually valid, which makes the resulting empty match confusing to diagnose.
saying these in an interview costs you the question
- Thinking >> is the CSS child combinator repeated
- Assuming every part is queried against the document root
- Expecting a chain to resolve to the first part by default
- Putting the capture asterisk on more than one part of a chain
- Leaving a literal >> unquoted inside a text body