Skip to main content
UI CoveragePremium Solution

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:

The UI Coverage report listing thousands of untested elements, several of which appear under machine-generated names derived from their DOM structure

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.

The App Quality tab of a project's settings in Cypress Cloud, showing the configuration editor with JSON configuration

Syntax

App Quality Config
{
"uiCoverage": {
"elementGroups": [
{
"selector": string,
"name": string,
"documentScope": [string],
"comment": string
}
]
}
}

Options

OptionRequiredDefaultDescription
selectorRequiredA CSS selector matched against each interactive element. Supports standard CSS selector syntax, including IDs, classes, attributes, combinators, and functional pseudo-classes like :has().
nameOptionalselectorA human-readable name for the group, displayed in UI Coverage reports. Each group's name must be unique.
documentScopeOptionalAn 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.
commentOptionalA 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 elementGroups rule is grouped by that rule alone. This includes links, which would otherwise be grouped by their href patterns.
  • A group forms even with one match. Unlike the automatic rules, which require at least two similar elements, an elementGroups rule that matches a single element still produces a named group in the report.
  • Filtered elements are never grouped. Elements excluded from reports by elementFilters are not considered for grouping.
  • The data-cy-ui-group attribute wins. Elements that declare a group directly in your markup with the data-cy-ui-group attribute keep that group, even if they also match an elementGroups rule.

Validation rules

Cypress Cloud rejects a configuration when:

  • Two rules have the same selector (with the same documentScope). Duplicates can never both apply, because the first matching rule wins.
  • Two rules have the same name, or one rule's name matches another rule's selector. Groups are identified by these values, so they must be unique.
  • A selector or documentScope entry isn't valid CSS selector syntax.
  • documentScope is 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

App Quality 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

App Quality 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

App Quality 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

App Quality 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

App Quality 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

App Quality 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

App Quality 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"].

tip

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 elementGroups rule matches, and the data-cy-ui-group markup attribute.
  • elements assigns a stable identity and name to a single element rather than a group.
  • elementFilters removes 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.