Group related elements - elementGroups
The elementGroups configuration combines related elements into a single unit in your UI Coverage report. A group counts once toward your coverage score, and an interaction with any element in the group marks the whole group as tested. This means a list of 50 untested product cards no longer appears as 50 untested elements dragging down your score. Instead, it appears as one clearly named group that a single test can cover.
Without meaningful groups, a report can fill up with elements listed under machine-generated names that are hard to act on:

Why use elementGroups?
UI Coverage already groups elements automatically based on their structure in the DOM. Use elementGroups when the automatic grouping doesn't match how your application actually behaves:
- Consolidate repeated elements: Collapse dynamic or repeated elements, such as items in a list, carousel, or data table, into one logical group.
- Correct the automatic grouping: Split apart elements that were grouped together incorrectly, or unite elements that the automatic rules kept separate.
- Make reports readable: Replace machine-generated selectors with meaningful names like "Remove Item Button" or "Shipping Method Option", so anyone reading the report understands what needs testing.
- Group across markup differences: Combine elements that share behavior but not structure, such as form controls and their labels.
If your goal is different, such as renaming a single element or removing elements from reports entirely, see Which option do I need? in the configuration overview.
Setting elementGroups
To add or edit elementGroups, open the App Quality tab in your project settings in Cypress Cloud. See Setting configuration for details, including how to regenerate past reports with a new configuration without rerunning your tests.

Syntax
{
"uiCoverage": {
"elementGroups": [
{
"selector": string,
"name": string,
"documentScope": [string],
"comment": string
}
]
}
}
Options
| Option | Required | Default | Description |
|---|---|---|---|
selector | Required | A CSS selector matched against each interactive element. Supports standard CSS selector syntax, including IDs, classes, attributes, combinators, and functional pseudo-classes like :has(). | |
name | Optional | selector | A human-readable name for the group, displayed in UI Coverage reports. Each group's name must be unique. |
documentScope | Optional | An ordered array of CSS selectors that match document hosts (iframes or shadow DOM hosts) in the element's ancestor chain, from outermost to innermost. Use this to group only elements inside a specific iframe or shadow DOM. Hosts that aren't listed may appear between the ones that are. | |
comment | Optional | A note about why this rule exists, for your team's benefit. Comments have no effect on how elements are grouped. |
How are elementGroups rules applied?
Rules are evaluated in order, and each element joins the group of the first rule whose selector matches it. Elements that match no rules fall back to the automatic element grouping rules.
A few behaviors are worth knowing:
- Custom groups override automatic grouping. An element that matches an
elementGroupsrule is grouped by that rule alone. This includes links, which would otherwise be grouped by theirhrefpatterns. - A group forms even with one match. Unlike the automatic rules, which require at least two similar elements, an
elementGroupsrule that matches a single element still produces a named group in the report. - Filtered elements are never grouped. Elements excluded from reports by
elementFiltersare not considered for grouping. - The
data-cy-ui-groupattribute wins. Elements that declare a group directly in your markup with thedata-cy-ui-groupattribute keep that group, even if they also match anelementGroupsrule.
Validation rules
Cypress Cloud rejects a configuration when:
- Two rules have the same
selector(with the samedocumentScope). Duplicates can never both apply, because the first matching rule wins. - Two rules have the same
name, or one rule'snamematches another rule'sselector. Groups are identified by these values, so they must be unique. - A
selectorordocumentScopeentry isn't valid CSS selector syntax. documentScopeis present but empty. Omit the property to match in any document.- A rule contains a property other than the four listed above.
Examples
Consolidate repeated elements
Elements generated from data often have dynamic attribute values, like an add to cart button rendered for each product in a listing. One rule with an attribute prefix selector collapses all of them into a single group. Without a name, the group is displayed under its selector.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "[data-cy^='add-to-cart-']"
}
]
}
}
HTML
<body>
<button data-cy="add-to-cart-101">Add to Cart</button>
<button data-cy="add-to-cart-102">Add to Cart</button>
<button data-cy="add-to-cart-103">Add to Cart</button>
</body>
Elements shown in UI
Without the rule, the result depends on the automatic grouping heuristics. The buttons may appear individually or under a machine-generated name:
[data-cy="add-to-cart-101"]
[data-cy="add-to-cart-102"]
[data-cy="add-to-cart-103"]
With the rule, the buttons always appear as one group:
[data-cy^='add-to-cart-'] (3 instances)
Give a group a readable name
Add a name so the report describes the interface instead of your selectors. Here, the remove buttons in a shopping cart appear as a single "Remove Item Button" group, no matter which products the cart contains.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "[id^='remove-item-']",
"name": "Remove Item Button"
}
]
}
}
HTML
<body>
<button id="remove-item-101">Remove</button>
<button id="remove-item-102">Remove</button>
<button id="remove-item-103">Remove</button>
<button id="remove-item-104">Remove</button>
</body>
Elements shown in UI
Remove Item Button (4 instances)
Order specific rules before broad ones
Each element joins the first rule that matches it, so list narrower rules first. Here, the featured product's button gets its own group because its rule comes before the catch-all rule. If the rules were reversed, the catch-all would capture all three buttons and the "Featured Buy Now Button" rule would never match anything.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "[data-cy='buy-now-featured']",
"name": "Featured Buy Now Button"
},
{
"selector": "[data-cy^='buy-now-']",
"name": "Buy Now Button"
}
]
}
}
HTML
<body>
<button data-cy="buy-now-featured">Buy Now</button>
<button data-cy="buy-now-101">Buy Now</button>
<button data-cy="buy-now-102">Buy Now</button>
</body>
Elements shown in UI
Featured Buy Now Button (1 instance)
Buy Now Button (2 instances)
Group all elements in a container
Use a descendant combinator to group every interactive element inside a container. This example collapses a delivery date picker's day buttons, which would otherwise appear as dozens of separate elements, into one group. The selector must match the interactive elements themselves, not just the container.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "#datepicker button",
"name": "Datepicker Day"
}
]
}
}
HTML
<body>
<div id="datepicker">
<button id="day-1">1</button>
<button id="day-2">2</button>
<button id="day-3">3</button>
</div>
</body>
Elements shown in UI
Datepicker Day (3 instances)
Group form controls with their labels
A comma-separated selector list can unite elements with different markup. This example groups a checkout page's shipping method radio inputs together with their clickable labels, using :has() to match the labels.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "input[name='shipping'], label:has(input[name='shipping'])",
"name": "Shipping Method Option"
}
]
}
}
HTML
<body>
<label>
<input type="radio" id="standard" name="shipping" />
Standard
</label>
<label>
<input type="radio" id="express" name="shipping" />
Express
</label>
</body>
Elements shown in UI
Shipping Method Option (4 instances)
Group elements inside a shadow DOM
Third-party widgets and design system components often render inside a shadow DOM. Use documentScope to apply a rule only to elements inside a specific shadow DOM host. Here, only the buttons inside the <support-chat> component's shadow root are grouped; the button in the main document also matches the button selector, but stays separate because it's outside the scope.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "button",
"name": "Support Chat Actions",
"documentScope": ["support-chat"]
}
]
}
}
HTML
<body>
<button id="open-support-chat">Chat with us</button>
<support-chat>
#shadow-dom
<button id="send-message">Send</button>
<button id="attach-file">Attach</button>
</support-chat>
</body>
Elements shown in UI
#open-support-chat
Support Chat Actions (2 instances)
Group elements inside an iframe
documentScope works the same way for embedded services that render inside an iframe, such as a payment provider on a checkout page. The scope selector matches the iframe element itself in its parent document. Here, only the buttons inside the #payment-provider iframe are grouped, while the coupon button in the main document remains a separate element.
Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": "[data-action]",
"name": "Payment Widget Actions",
"documentScope": ["#payment-provider"]
}
]
}
}
HTML
<body>
<button data-action="apply-coupon">Apply Coupon</button>
<iframe id="payment-provider" src="https://payments.example.com">
<html>
<body>
<button data-action="submit-payment">Pay Now</button>
<button data-action="change-method">Change Payment Method</button>
</body>
</html>
</iframe>
</body>
Elements shown in UI
[data-action="apply-coupon"]
Payment Widget Actions (2 instances)
For nested documents, list one selector per host from outermost to innermost, for example "documentScope": ["#payment-provider", "secure-card-input"].
After saving configuration changes, regenerate a recent run to preview your groups without rerunning your tests. See Setting configuration for how to regenerate a report.
See also
- Element Grouping explains the automatic grouping rules that apply when no
elementGroupsrule matches, and thedata-cy-ui-groupmarkup attribute. elementsassigns a stable identity and name to a single element rather than a group.elementFiltersremoves elements from reports entirely instead of grouping them.- Configuration overview covers where configuration lives and how to regenerate reports after changing it.
- Guide: Reduce noise in UI Coverage reports walks through combining these options to clean up a report.
- UI Coverage FAQ answers common questions about grouping, scores, and configuration.