A Unique Element Locator (UEL) is a path that identifies where an element is in the document. Most look like CSS selectors, but when shadow DOMs or iFrames are involved, UELs add special markers (| and ||). These markers show boundary crossings and make the UEL unusable as a standard CSS selector.
On this page:
UEL Markers
UELs use special markers to indicate different document boundaries:
| Marker | Meaning |
|---|---|
| | | Crossing a shadowDOM boundary |
| || | Crossing an iFrame boundary |
Shadow DOM example
body > div:nth-of-type(5) | :host > *:nth-child(1) > *:nth-child(1)This represents:
- A
<div>that is the fifth child<div>of the<body>. - That
<div>element has a shadow DOM attached. - Within the shadow DOM,
:hostrepresents the root element. - Within the shadow DOM root the locator shows the first child has a child.
- The first child of the first child is the node of interest.
Each | transition indicates entering a shadow DOM, where the contained elements are isolated from the main document. Shadow DOMs can be nested within shadow DOMs so there could be multiple | in the UEL.
iFrame example
body>iframe:nth-of-type(1)||body>img:nth-of-type(1)This represents:
- An
<iframe>that is the first child<iframe>of the<body>. - Inside the
<body>of that<iframe>, the locator points to an<img>. - The
<img>that is the first child<img>of the<iframe>'s<body>and is the node of interest.
Each || transition indicates entering an iFrame, isolating its contents from the main document. Iframes can be nested within Iframes so there could be multiple || in the UEL
Shadow DOM + iFrame Example
body>div:nth-of-type(1)|:host>*:iframe:nth-of-type(1)||body>div:nth-of-type(1)This represents:
- The
<div>is the first child<div>of the<body>. - That <div> has a shadow DOM attached.
- Within the shadow DOM,
:hostrepresents the root element. - Inside the shadow DOM, an
<iframe>is the first child<iframe>of the:host. - Inside the
<body>of that<iframe>, there is a<div>that is the first child<div>of that<body>. - This
<div>is the node of interest.
Each | or || indicates a boundary transition either into a shadow DOM or into an iFrame. Multiple shadow DOMs and iframes can be nested within each other so there could be multiple | and || in the UEL.
Why standard CSS selectors don’t work
By design, CSS selectors cannot cross shadow DOM or iFrame boundaries. Shadow DOMs and iFrames encapsulate their contained content, preventing direct selection from the main document. In order to provide the full path to encapsulated flagged nodes, UELs enhance the CSS selector format to add markers to represent encapsulation boundaries. These same enhancements mean UELs cannot be parsed as standard CSS when shadow DOMs or iFames are in play.
Example that fails in CSS:
body > div:nth-of-type(5) | :host > *:nth-child(1) > *:nth-child(1)Use UELs in automation and APIs
UELs are not directly usable in APIs or automation tools that expect standard CSS selectors. If a UEL contains | or || you must break it into steps and handle each boundary explicitly.
iFrame Playwright example (JavaScript)
// Locate the iframe
const frame = await page.frameLocator('iframe#iframe-container');
// Locate the element inside the iframe
const element = await frame.locator('div#inside-iframe button.flagged');
// Interact with the element
await element.click();Step breakdown
-
page.frameLocator('iframe#iframe-container'): Switches context into the iFrame. -
frame.locator('div#inside-iframe button.flagged'): Finds the button inside the iframe. -
element.click(): Interacts with the element.
Syntax differs across tools
- For shadow DOM: Open the shadow root.
- For iframes: Switch frame context.
Shadow DOM Playwright example (JavaScript)
// Locate the shadow host
const host = await page.locator('div#shadow-host');
// Open the shadow root
const shadowRoot = await host.evaluateHandle(el => el.shadowRoot);
// Locate the element inside the shadow root
const element = await shadowRoot.$('button.flagged');
// Interact with the element
element.click();-
locator('div#shadow-host'): Finds the element that owns the shadow DOM. -
evaluateHandle(el => el.shadowRoot): Enters the shadow DOM context. -
shadowRoot.$('button.flagged') within shadowRoot: Finds the element inside the shadow DOM. -
innerElement.click(): Interacts with the targeted element.
APIs Expecting Selectors
APIs that expect standard CSS selectors will only work with UELs if they don’t contain | or ||, meaning they have no shadow DOM or iFrames in the path.
- Works:
div#content > button.save(UEL without boundary markers). - Fails:
iframe#id || div#inside(UEL with iFrame boundary).
To work with encapsulated content, you must parse the UEL, handle boundary transitions, and then apply the CSS selector within the correct context.
Comments
0 comments
Article is closed for comments.