{
  "doc": {
    "id": "accessibility/configuration/attributefilters",
    "title": "attributeFilters: control element identification in Cypress Accessibility",
    "description": "Use attributeFilters to stop dynamic, auto-generated, or state-based attributes from splitting one element into many or mis-grouping violations in Cypress Accessibility reports.",
    "section": "accessibility",
    "source_path": "/llm/markdown/accessibility/configuration/attributefilters.md",
    "version": "fbc9225067c51c52ee13224e3b702cf8a025ec12",
    "updated_at": "2026-08-14T12:36:26.878Z",
    "headings": [
      {
        "id": "accessibility/configuration/attributefilters#ignore-attributes-for-identification-attributefilters",
        "text": "Ignore attributes for identification - attributeFilters",
        "level": 1
      },
      {
        "id": "accessibility/configuration/attributefilters#why-use-attributefilters",
        "text": "Why use attributeFilters?",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#built-in-filters",
        "text": "Built-in filters",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#scope",
        "text": "Scope",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#setting-attributefilters",
        "text": "Setting attributeFilters",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#syntax",
        "text": "Syntax",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#options",
        "text": "Options",
        "level": 3
      },
      {
        "id": "accessibility/configuration/attributefilters#how-rules-are-applied",
        "text": "How rules are applied",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#examples",
        "text": "Examples",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#excluding-framework-generated-ids",
        "text": "Excluding framework-generated IDs",
        "level": 3
      },
      {
        "id": "accessibility/configuration/attributefilters#html",
        "text": "HTML",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#element-identifiers-displayed",
        "text": "Element identifiers displayed",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#filtering-an-id-and-the-attributes-that-reference-it",
        "text": "Filtering an ID and the attributes that reference it",
        "level": 3
      },
      {
        "id": "accessibility/configuration/attributefilters#html",
        "text": "HTML",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#element-identifiers-displayed",
        "text": "Element identifiers displayed",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#keeping-one-attribute-while-excluding-a-whole-family",
        "text": "Keeping one attribute while excluding a whole family",
        "level": 3
      },
      {
        "id": "accessibility/configuration/attributefilters#html",
        "text": "HTML",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#element-identifiers-displayed",
        "text": "Element identifiers displayed",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#grouping-repeated-elements-by-ignoring-per-row-ids",
        "text": "Grouping repeated elements by ignoring per-row IDs",
        "level": 3
      },
      {
        "id": "accessibility/configuration/attributefilters#html",
        "text": "HTML",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#element-identifiers-displayed",
        "text": "Element identifiers displayed",
        "level": 4
      },
      {
        "id": "accessibility/configuration/attributefilters#confirming-a-filter-worked",
        "text": "Confirming a filter worked",
        "level": 2
      },
      {
        "id": "accessibility/configuration/attributefilters#see-also",
        "text": "See also",
        "level": 2
      }
    ]
  },
  "chunks": [
    {
      "id": "accessibility/configuration/attributefilters#why-use-attributefilters",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Why use attributeFilters?",
      "heading_level": 2,
      "content_markdown": "## Why use attributeFilters?\n\n*   **Stop duplicate elements**: When an element's `id`, `class`, or other attribute is regenerated on each render, the same control is counted many times. Filtering the volatile attribute lets Cypress identify it consistently.\n*   **Improve grouping accuracy**: Removing attributes that differ between otherwise-identical elements (for example a per-row `data-cy=\"user-123\"`) lets Cypress group them as one repeated component.\n*   **Ignore library-specific attributes**: Attributes injected by frameworks (Angular's `ng-*`, Emotion/JSS hashed classes, and similar) rarely describe an element's purpose and often add noise.\n\nIf instead you want Cypress to _prefer_ a particular attribute as an identifier when it is available, use [`significantAttributes`](/llm/markdown/ui-coverage/configuration/significantattributes.md). `attributeFilters` only ever removes attributes from consideration; it never promotes them.\n",
      "section": "accessibility",
      "anchors": [
        "why-use-attributefilters"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 153
    },
    {
      "id": "accessibility/configuration/attributefilters#built-in-filters",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Built-in filters",
      "heading_level": 2,
      "content_markdown": "## Built-in filters\n\nCypress already excludes the most common sources of unstable identifiers, such as auto-generated IDs and hashed CSS classes, so many applications need no `attributeFilters` configuration at all.\n\nYour configured rules run **before** these built-in filters, so a rule with `include: true` can re-enable an attribute that a built-in filter would otherwise drop. Add `attributeFilters` when your application produces unstable identifiers that these defaults don't already cover.\n",
      "section": "accessibility",
      "anchors": [
        "built-in-filters"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 92
    },
    {
      "id": "accessibility/configuration/attributefilters#scope",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Scope",
      "heading_level": 2,
      "content_markdown": "## Scope\n\n**Note:** setting `attributeFilters` at the root of your configuration impacts both UI Coverage and Cypress Accessibility reports. To configure the products separately, nest the property under a `uiCoverage` or `accessibility` key. A nested `attributeFilters` completely replaces a root-level one for that product; the two lists are not merged.\n",
      "section": "accessibility",
      "anchors": [
        "scope"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 67
    },
    {
      "id": "accessibility/configuration/attributefilters#setting-attributefilters",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Setting attributeFilters",
      "heading_level": 2,
      "content_markdown": "## Setting attributeFilters\n\nTo add or edit `attributeFilters`, open the **App Quality** tab in your project settings in Cypress Cloud. See [Setting configuration](/llm/markdown/ui-coverage/configuration/overview.md#Setting-configuration) for details, including how to regenerate past reports with a new configuration without rerunning your tests.\n",
      "section": "accessibility",
      "anchors": [
        "setting-attributefilters"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 52
    },
    {
      "id": "accessibility/configuration/attributefilters#syntax",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Syntax",
      "heading_level": 2,
      "content_markdown": "## Syntax\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": string,      \"value\": string,      \"include\": boolean,      \"comment\": string    }  ]}\n```\n\nTo scope rules to a single product, nest the property under a `uiCoverage` or `accessibility` key, as described in [Scope](#Scope) above.\n\n### Options\n\n| Option | Required | Default | Description |\n| --- | --- | --- | --- |\n| `attribute` | Required |  | A regular expression matched against attribute names. Must be a valid HTML attribute name. |\n| `value` | Optional | `.*` | A regular expression matched against the attribute's value. |\n| `include` | Optional | `true` | Whether the matched attribute may be used for identification (`true`) or is ignored (`false`). |\n| `comment` | Optional |  | A note about why this rule exists, for your team's benefit. Comments appear only in the configuration itself. They have no effect on identification and are not displayed in reports. |\n\nEach rule accepts only these four properties. Cypress Cloud validates your configuration and rejects any unrecognized property, as well as two rules that are exactly identical.\n",
      "section": "accessibility",
      "anchors": [
        "syntax"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 245
    },
    {
      "id": "accessibility/configuration/attributefilters#options",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Options",
      "heading_level": 3,
      "content_markdown": "### Options\n\n| Option | Required | Default | Description |\n| --- | --- | --- | --- |\n| `attribute` | Required |  | A regular expression matched against attribute names. Must be a valid HTML attribute name. |\n| `value` | Optional | `.*` | A regular expression matched against the attribute's value. |\n| `include` | Optional | `true` | Whether the matched attribute may be used for identification (`true`) or is ignored (`false`). |\n| `comment` | Optional |  | A note about why this rule exists, for your team's benefit. Comments appear only in the configuration itself. They have no effect on identification and are not displayed in reports. |\n\nEach rule accepts only these four properties. Cypress Cloud validates your configuration and rejects any unrecognized property, as well as two rules that are exactly identical.\n",
      "section": "accessibility",
      "anchors": [
        "options"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 189
    },
    {
      "id": "accessibility/configuration/attributefilters#how-rules-are-applied",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "How rules are applied",
      "heading_level": 2,
      "content_markdown": "## How rules are applied\n\nWhether Cypress may use an attribute to identify an element is decided by the **first** rule whose `attribute` and `value` both match. Because the first match wins, order your rules from most specific to least specific: put `include: true` exceptions first, then broader `include: false` catch-all rules. For example, you can exclude every `aria-label` from identification with a catch-all rule, while keeping a few known-stable values by listing `include: true` rules for them first.\n\nAn attribute that matches no rule is available for use, so `include: true` is only needed to define exceptions.\n\nKeep these matching details in mind when writing patterns:\n\n*   **Patterns match the whole string.** Each `attribute` and `value` pattern is anchored automatically, as if wrapped in `^(...)$`, so it must match the entire name or value. Use wildcards for partial matches: `value: \"user-.*\"` matches `user-123`, whereas `value: \"user\"` matches only the exact string `user`. If your pattern already starts with `^` or ends with `$`, it is used as written.\n*   **Escape backslashes for JSON.** Because JSON uses the backslash as its own escape character, a regex token like `\\d` must be written `\\\\d` in the configuration. A single backslash is dropped, turning `\\d` into a literal `d` that matches nothing you intended.\n*   **Attribute names are matched case-insensitively; values are matched case-sensitively.**\n*   **Only attributes and individual `class` tokens can be filtered.** Rules never apply to an element's tag name or its position among siblings (`nth-child`), which Cypress may still fall back to when no attributes are usable.\n",
      "section": "accessibility",
      "anchors": [
        "how-rules-are-applied"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 344
    },
    {
      "id": "accessibility/configuration/attributefilters#examples",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Examples",
      "heading_level": 2,
      "content_markdown": "## Examples\n\n### Excluding framework-generated IDs\n\nReact's `useId` hook (used by libraries like MUI and Radix) produces `id` values such as `:r0:` that change on every render. Excluding them lets Cypress identify each field by its stable `name` instead.\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"id\",      \"value\": \":r.*\",      \"include\": false,      \"comment\": \"React useId() values are regenerated on every render\"    }  ]}\n```\n\n#### HTML\n\n```\n<form>  <input id=\":r0:\" name=\"email\" type=\"email\" />  <input id=\":r1:\" name=\"password\" type=\"password\" /></form>\n```\n\n#### Element identifiers displayed\n\n```\n[name=\"email\"][name=\"password\"]\n```\n\n* * *\n\n### Filtering an ID and the attributes that reference it\n\nWhen you filter a dynamic `id`, also filter the attributes that point at it, or elements will still be identified by those related dynamic values. Here Angular Material generates `mat-*` IDs and wires them through `for` and `aria-describedby`. Common relationships to filter alongside an `id` include:\n\n*   Form associations (`for` on labels)\n*   ARIA relationships (`aria-labelledby`, `aria-describedby`, `aria-controls`, `aria-owns`, `aria-details`)\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"id|for|aria-describedby|aria-labelledby\",      \"value\": \"mat-.*\",      \"include\": false,      \"comment\": \"Angular Material regenerates mat-* ids per render\"    }  ]}\n```\n\n#### HTML\n\n```\n<div>  <label for=\"mat-input-0\">Email</label>  <input id=\"mat-input-0\" name=\"email\" aria-describedby=\"mat-hint-2\" />  <span id=\"mat-hint-2\">We'll only use this to sign you in.</span></div>\n```\n\n#### Element identifiers displayed\n\n```\nlabel[name=\"email\"]span\n```\n\n* * *\n\n### Keeping one attribute while excluding a whole family\n\nBecause the first matching rule wins, an `include: true` rule listed before a broad `include: false` rule protects the attributes it matches. Here Cypress keeps identifying elements by your `data-cy` test hook while ignoring the stateful `data-*` attributes that component libraries add and change as the UI updates.\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"data-cy\",      \"include\": true,      \"comment\": \"Always identify elements by our test hook\"    },    {      \"attribute\": \"data-.*\",      \"include\": false,      \"comment\": \"Ignore library state attributes like data-state, data-headlessui-state\"    }  ]}\n```\n\n#### HTML\n\n```\n<button data-cy=\"menu-toggle\" data-headlessui-state=\"open\" data-state=\"active\">  Menu</button>\n```\n\n#### Element identifiers displayed\n\n```\n[data-cy=\"menu-toggle\"]\n```\n\n* * *\n\n### Grouping repeated elements by ignoring per-row IDs\n\nFiltering a per-instance value lets Cypress group otherwise-identical elements into a single repeated component instead of tracking each row separately. Here each delete button carries the row's database ID, so removing that value collapses them into one group.\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"id\",      \"value\": \"delete-user-\\\\d+\",      \"include\": false,      \"comment\": \"Row action ids include the per-user database id\"    }  ]}\n```\n\n#### HTML\n\n```\n<button id=\"delete-user-4821\" class=\"delete-btn\">Delete</button><button id=\"delete-user-9034\" class=\"delete-btn\">Delete</button>\n```\n\n#### Element identifiers displayed\n\n```\n.delete-btn (2 instances)\n```\n",
      "section": "accessibility",
      "anchors": [
        "examples"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 559
    },
    {
      "id": "accessibility/configuration/attributefilters#excluding-framework-generated-ids",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Excluding framework-generated IDs",
      "heading_level": 3,
      "content_markdown": "### Excluding framework-generated IDs\n\nReact's `useId` hook (used by libraries like MUI and Radix) produces `id` values such as `:r0:` that change on every render. Excluding them lets Cypress identify each field by its stable `name` instead.\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"id\",      \"value\": \":r.*\",      \"include\": false,      \"comment\": \"React useId() values are regenerated on every render\"    }  ]}\n```\n\n#### HTML\n\n```\n<form>  <input id=\":r0:\" name=\"email\" type=\"email\" />  <input id=\":r1:\" name=\"password\" type=\"password\" /></form>\n```\n\n#### Element identifiers displayed\n\n```\n[name=\"email\"][name=\"password\"]\n```\n\n* * *\n",
      "section": "accessibility",
      "anchors": [
        "excluding-framework-generated-ids"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 117
    },
    {
      "id": "accessibility/configuration/attributefilters#filtering-an-id-and-the-attributes-that-reference-it",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Filtering an ID and the attributes that reference it",
      "heading_level": 3,
      "content_markdown": "### Filtering an ID and the attributes that reference it\n\nWhen you filter a dynamic `id`, also filter the attributes that point at it, or elements will still be identified by those related dynamic values. Here Angular Material generates `mat-*` IDs and wires them through `for` and `aria-describedby`. Common relationships to filter alongside an `id` include:\n\n*   Form associations (`for` on labels)\n*   ARIA relationships (`aria-labelledby`, `aria-describedby`, `aria-controls`, `aria-owns`, `aria-details`)\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"id|for|aria-describedby|aria-labelledby\",      \"value\": \"mat-.*\",      \"include\": false,      \"comment\": \"Angular Material regenerates mat-* ids per render\"    }  ]}\n```\n\n#### HTML\n\n```\n<div>  <label for=\"mat-input-0\">Email</label>  <input id=\"mat-input-0\" name=\"email\" aria-describedby=\"mat-hint-2\" />  <span id=\"mat-hint-2\">We'll only use this to sign you in.</span></div>\n```\n\n#### Element identifiers displayed\n\n```\nlabel[name=\"email\"]span\n```\n\n* * *\n",
      "section": "accessibility",
      "anchors": [
        "filtering-an-id-and-the-attributes-that-reference-it"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 168
    },
    {
      "id": "accessibility/configuration/attributefilters#keeping-one-attribute-while-excluding-a-whole-family",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Keeping one attribute while excluding a whole family",
      "heading_level": 3,
      "content_markdown": "### Keeping one attribute while excluding a whole family\n\nBecause the first matching rule wins, an `include: true` rule listed before a broad `include: false` rule protects the attributes it matches. Here Cypress keeps identifying elements by your `data-cy` test hook while ignoring the stateful `data-*` attributes that component libraries add and change as the UI updates.\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"data-cy\",      \"include\": true,      \"comment\": \"Always identify elements by our test hook\"    },    {      \"attribute\": \"data-.*\",      \"include\": false,      \"comment\": \"Ignore library state attributes like data-state, data-headlessui-state\"    }  ]}\n```\n\n#### HTML\n\n```\n<button data-cy=\"menu-toggle\" data-headlessui-state=\"open\" data-state=\"active\">  Menu</button>\n```\n\n#### Element identifiers displayed\n\n```\n[data-cy=\"menu-toggle\"]\n```\n\n* * *\n",
      "section": "accessibility",
      "anchors": [
        "keeping-one-attribute-while-excluding-a-whole-family"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 151
    },
    {
      "id": "accessibility/configuration/attributefilters#grouping-repeated-elements-by-ignoring-per-row-ids",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Grouping repeated elements by ignoring per-row IDs",
      "heading_level": 3,
      "content_markdown": "### Grouping repeated elements by ignoring per-row IDs\n\nFiltering a per-instance value lets Cypress group otherwise-identical elements into a single repeated component instead of tracking each row separately. Here each delete button carries the row's database ID, so removing that value collapses them into one group.\n\nApp Quality Config\n\n```\n{  \"attributeFilters\": [    {      \"attribute\": \"id\",      \"value\": \"delete-user-\\\\d+\",      \"include\": false,      \"comment\": \"Row action ids include the per-user database id\"    }  ]}\n```\n\n#### HTML\n\n```\n<button id=\"delete-user-4821\" class=\"delete-btn\">Delete</button><button id=\"delete-user-9034\" class=\"delete-btn\">Delete</button>\n```\n\n#### Element identifiers displayed\n\n```\n.delete-btn (2 instances)\n```\n",
      "section": "accessibility",
      "anchors": [
        "grouping-repeated-elements-by-ignoring-per-row-ids"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 120
    },
    {
      "id": "accessibility/configuration/attributefilters#confirming-a-filter-worked",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "Confirming a filter worked",
      "heading_level": 2,
      "content_markdown": "## Confirming a filter worked\n\nYou don't need to rerun your tests to check a rule. Regenerate a historical run from its **Properties** tab and the report is reprocessed with your current configuration. Confirm the change by checking that an element that previously appeared multiple times now appears once, or that a set of repeated elements collapsed into a single entry.\n\nIf nothing changed, revisit [How rules are applied](#How-rules-are-applied). The most common causes are a pattern that doesn't fully match the value, an earlier rule taking precedence, or a report that was processed before the configuration was saved.\n",
      "section": "accessibility",
      "anchors": [
        "confirming-a-filter-worked"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 131
    },
    {
      "id": "accessibility/configuration/attributefilters#see-also",
      "doc_id": "accessibility/configuration/attributefilters",
      "heading": "See also",
      "heading_level": 2,
      "content_markdown": "## See also\n\n*   [`significantAttributes`](/llm/markdown/accessibility/configuration/significantattributes.md): prioritize the attributes Cypress should prefer as identifiers. This is the complement to filtering out the ones it should ignore.\n*   [Component attributes](/llm/markdown/accessibility/configuration/components.md): an Accessibility-only option (`componentAttributes` and `componentAttributeFilters`) that shapes which attributes appear in stable violation-target selectors.\n*   [Element identification](/llm/markdown/ui-coverage/core-concepts/element-identification.md): how elements are identified for both Cypress Accessibility and UI Coverage.\n*   [Configuration overview](/llm/markdown/accessibility/configuration/overview.md): where to set configuration and regenerate reports.\n*   [Cypress Accessibility FAQ](/llm/markdown/accessibility/faq.md): common questions and troubleshooting.\n",
      "section": "accessibility",
      "anchors": [
        "see-also"
      ],
      "path": "/llm/json/chunked/accessibility/configuration/attributefilters.json",
      "token_estimate": 100
    }
  ]
}