In Selenium 4, how do element references, shadow root references and window handles differ as identifiers?
answer
- Three shapes, not one
- Only one of them is a bare string
- Two are objects with fixed keys
- A different prefix for the shadow one
- One of them outlives the document
basics
~10 sElement and shadow root references are one-member JSON objects under different fixed keys, and both die with their document. A window handle is a bare string naming a tab, and it survives navigation.
solid answer
~40 sAll three are opaque driver-issued strings, but they differ in shape and lifetime. An element reference arrives as an object keyed `element-6066-11e4-a52e-4f735466cecf` and is valid only while its node stays attached to the active document. A shadow root reference uses a different key, `shadow-6066-11e4-a52e-4f735466cecf`, and `WebElement.getShadowRoot()` hands it back as a `SearchContext` rather than a `WebElement`; it is document-scoped in exactly the same way. A window handle from `getWindowHandle()` is a plain JSON string, not an object, and it names a top-level browsing context - so it is unchanged by navigation and stays valid until that tab closes. That is why a tab handle is safe to keep for a whole run and an element reference is not.
go deeper
Know that these are three different kinds of string and that they are not interchangeable, and that none of them is meant to be read or built by hand.
Explain the wire shapes: two one-member objects under different fixed keys, and a bare string for a window, plus which of them a navigation invalidates.
Demonstrate the lifetime judgment - which identifier may be held in a field for a whole run and which must be treated as valid only inside a single document.
Own the convention that keeps a suite honest about identity scope, so that context handles and node references are never stored by the same mechanism or with the same lifetime.
## Three different things a session hands back A Selenium 4 session gives a test three kinds of identifier, and they are easy to lump together because all three are strings a test stores in a variable. On the wire they are not the same shape at all, and they do not have the same lifetime. On a payroll approval queue built from a `<payroll-approval-card>` custom element, a single test can hold all three at once: a reference to the approve button, a reference to the card's shadow root, and the handle of the tab the queue is open in. ## Element references The Find Element command answers with a JSON object carrying the fixed key `element-6066-11e4-a52e-4f735466cecf`, whose value is an **opaque id** the remote end assigned to that DOM node. The Java client wraps it as a `WebElement`. Its validity is bounded by the document that produced it: once the node leaves that document, or the document stops being the active one, a command carrying the id is answered with `stale element reference`. ## Shadow root references `WebElement.getShadowRoot()` does not return a `WebElement`. On the wire the remote end answers with a different one-member object, keyed `shadow-6066-11e4-a52e-4f735466cecf`, and the Java client hands it back typed as a `SearchContext` - a thing you can search inside, not an element you can click or read text from. Two points follow: - A shadow root reference and an element reference are **different key spaces**; the remote end will not accept one where it expects the other. - A shadow root reference is **document-scoped in exactly the same way**. Replace the host card and the old root reference is as dead as a reference to the button inside it. ## Window handles `driver.getWindowHandle()` and `driver.getWindowHandles()` answer with **plain strings** - not an object, not a key-and-value pair. A window handle names a **top-level browsing context**: a tab or a window, not a frame inside one. Its lifetime is completely different from the other two: - It is stable across navigation. Loading a new payroll page into the same tab keeps the handle unchanged. - It stays valid for as long as that tab exists, and becomes unusable when the tab closes. - It is still opaque. It is a driver-chosen string, never an index into a list of tabs, so arithmetic on it is meaningless. ## Side by side | Identifier | Wire shape | Valid while | Java surface | |---|---|---|---| | element reference | object keyed `element-6066-11e4-a52e-4f735466cecf` | its document is active and the node is attached | `WebElement` | | shadow root reference | object keyed `shadow-6066-11e4-a52e-4f735466cecf` | its host's document is active and the host is attached | `SearchContext` | | window handle | bare JSON string | the tab or window exists | `String` | ## Why the distinction is worth holding The three lifetimes are the reason a payroll test can keep the tab handle in a field for the whole run and must not do the same with the approve button. A handle that survives navigation and a reference that dies with the document look identical in the source - both are just values a test kept - so the only way to reason about which one is safe to hold is to know what each denotes on the wire. 1. Element and shadow root references denote **nodes in one document**, and the remote end resolves them against the known-elements cache for that browsing context. 2. A window handle denotes **the browsing context itself**, which outlives every document loaded into it. 3. None of the three is human-readable, and none may be constructed, parsed or guessed by a test. Two more things worth knowing about window handles specifically: - `getWindowHandles()` enumerates top-level browsing contexts only; a frame embedded in the payroll page does not get a handle of its own. - The set is unordered, so the handle of a newly opened window is found by comparing against the handles you already had, never by taking a position in the returned collection. This split is a Selenium 4 and W3C WebDriver picture. The shadow root key in particular has no Selenium 3 equivalent: shadow DOM access arrived with the W3C protocol, and there was no earlier spelling of it to be compatible with.
- What happens to a shadow root reference when its host element is replaced?It goes stale by the same rule that kills an element reference. The old host node is no longer connected to the active document, so the reference the driver issued against it can no longer be dereferenced, even though the new card renders an identical shadow tree with identical contents.
- Is a window handle guaranteed to stay the same for the life of a tab?Yes. The handle names the top-level browsing context rather than any document loaded into it, so navigating the tab to another payroll page leaves it unchanged. It becomes unusable only when that tab or window is closed, and the driver never reissues it for a different context.
- Does every frame on a page get a window handle of its own?No. Get Window Handles enumerates top-level browsing contexts only, so an iframe embedded in the payroll queue never appears in the returned set. The collection is also unordered, so a newly opened window is identified by comparing against the handles you already held, not by position.
saying these in an interview costs you the question
- Treats a window handle as an element reference
- Thinks a shadow root uses the element key
- Expects an element reference to survive navigation
- Believes window handles are numeric tab indexes
- Assumes a shadow root reference never goes stale