[Feature]: all locators only select visible elements by default
🚀 Feature Request
Please add an option or other possibility to set all locators to ignore invisible elements by default. Currently this is not possible and people have to add .locator('visible=true') or newly introduced .filter({ visible: true }) everywhere which is easy to forget and pollutes the tests.
Consider making it a default behavior in the future versions.
Example
This would introduce a new option in the Playwright config selectInvisibleElements: boolean (or similar with better name) to allow locators select invisible elements by default or not as discussed in https://github.com/microsoft/playwright/issues/31840.
As stated in https://github.com/microsoft/playwright/issues/31840#issuecomment-2260158837 this may be trimodal option but when using it as option in the config I believe 2 options have more sense.
Motivation
For testing a react-native-web applications this is really important because the routing works by hiding the pages and stack them one on another. Then selecting base things like navigation can lead to multiple elements found in all tests. Adding a global option to ignore invisible/hidden elements would be really a great help here so we don't have to add .filter({ visible: true }) to every selector.
The package react-native-testing-library changed the default behavior to exclude elements hidden from accessibility by default so maybe you can inspire or talk to them about this. It was a big help for our tests.
I understand this may be seen as a breaking change but I believe this is a good one. Considering people are currently probably testing with selectors catching on hidden elements they would actually catch bugs in their code after a break change. I can imagine someone not practicing TDD and not seeing red test in the first place writing a green test assuming everything is working when the actual user would not be able to do an action because of some hidden element. So it's more like fixing an important bug in the testing framework :) Also, for people whose tests are properly written nothing would break because they are already selecting visible elements.
In conclusion, this is only a breaking change for people with false-green tests and by updating they catch bugs in their app. Also, if that helps, it is possible without hard breaking change. With config flag and a warning, everyone can migrate smoothly, fix this issue with config and then migrate on next version with turned this by default.
Implementation thoughts: this could be similar to contextOptions.strictSelectors with the same declaration and plumbing. Leaving the issue open for prioritization.
Is there any update on this?
I believe this is also needed for React applications where streaming SSR emits content as hidden divs at the end of the HTML, with scripts to move/copy things into place. I have sporadic strict mode violation errors due to Playwright matching the visible content and also duplicated elements inside these hidden divs created by React.
Error: locator.fill: Error: strict mode violation: getByLabel('First name') resolved to 2 elements:
1) <input required="" type="text" name="first_name"/> aka getByRole('textbox', { name: 'First name' })
2) <input type="text" required="" name="first_name"/> aka getByLabel('First name').nth(1)
Call log:
- waiting for getByLabel('First name')
44 | test('example', async ({ page }) => {
45 | await page.goto('/join');
> 46 | await page.getByLabel('First name').fill('Bear');
| ^
47 | });
In case it helps anyone else, I was able to workaround this using getByRole which excludes hidden elements by default (unlike getByText for example).
I believe this is also needed for React applications where streaming SSR emits content as hidden divs at the end of the HTML
@OliverJAsh Thanks for the insights! My tests have been flaky for a while and I couldn't figure out the exact root cause. I suspected it was due to React hydration and elements somehow gets duplicated during a short transition time, and with your information I am able to confirm the tests were failed due to the hidden divs.
In my case I use getByTestId which is suppose to uniquely locate exact one element in my code, and the hidden elements are really confusing.
I think either this request to only select visible elements by default, or automatically wait to resolve strict mode violation (https://github.com/microsoft/playwright/issues/36045) would be helpful for the React use case. Alternatively, a config option to opt in for only select visible elements globally would work too.
I'd like to highlight that this feature request is about to become significantly more critical due to upcoming architectural shifts in the Next.js ecosystem.
As detailed in the Next.js documentation, when the cacheComponents flag is enabled the framework will now default to keeping previously visited routes in the DOM (marked as hidden/inert) rather than unmounting them.
In this new architecture, a simple navigation often results in two instances of the UI existing simultaneously in the DOM:
- The user-visible version.
- The cached, display: none version from the previous "activity."
Without a global configuration for visibility (as requested in this issue), developers adopting modern Next.js features will be forced to append .filter({ visible: true }) to virtually every locator interaction to avoid strict mode violations. This creates massive boilerplate and DX friction for what is effectively the "soon to be" default behavior of the framework.
Given that this "keep-alive" pattern is becoming a standard in modern web frameworks to enhance UX, Playwright needs a native, ergonomic way to handle "offscreen" or "inactive" subtrees without requiring verbose filtering on every line of test code.
I'd like to take a crack at this.
I plan to implement the visibleOnly parameter (alongside strictSelectors) with a default of false. This ensures backward compatibility and keeps the implementation lightweight/easy to review.
I understand this is P3, but since the scope is small, I hope it can be considered.
I understand this is P3, but since the scope is small, I hope it can be considered.
The scope is in fact substantial, I don't think a non-core team member can tackle this.
This is an important and even foundational capability. If it isn’t fixed, the user is forced to take on the cognitive load themselves, which can easily result in unexpected failures.