data-* attributes on its elements. The library owns data-anv and data-anv-part. You own data-tracking-id when you pass one, and you own the instance id on the component root.
data-anv
data-anv is a library-owned marker. A button root is data-anv="button". A dialog root is data-anv="dialog". Nested pieces use their own names, such as data-anv="dialog-header".
The library uses these names for styles and for keyboard focus queries. Do not pass data-anv yourself. A value you pass replaces the library value and can break those styles and queries. Do not use data-anv as an end-to-end test selector. data-anv-part is that contract.
A custom nested Menu trigger is the exception. Spread the data-anv value the menu provides onto that trigger so the item keeps menu styling and stays in the keyboard order. The Menu page describes that case.
data-anv-part
data-anv-part names an interactive sub-element so a test can target it. The library owns the part names. You supply the instance id.
Pass data-cy or data-testid on the component. Anvil2 forwards that attribute to the root. Scope the part query to that root.
data-anv and data-anv-part can sit on the same element. data-anv says which Anvil2 element it is. data-anv-part says which testable role it plays, such as input, trigger, or option.
Part names are unique within one component. The same name can appear on a different component. Scope the query with your instance id, or with the component’s data-anv value.
Some parts render in a portal, outside the component root. A query scoped to your data-cy does not reach them. Target those parts by data-anv-part on the document. Each component page lists its part names and calls out portal exceptions.
When one part repeats, the element also carries a discriminator such as data-id or data-anv-column-id. Use the discriminator to pick one row, option, or cell.
data-tracking-id
Button, form fields, links, menus, and other components that opt in write a data-tracking-id. Fullstory and other analytics tools read that attribute from the DOM.
The lookup is asynchronous. The attribute is missing on the first render.
The value is _${scope}_${component}_ plus a short cipher of the props that component includes. The same component name, the same payload, and the same scope always produce the same id. Two controls that share those inputs share an id. Each component chooses its own payload. When the payload includes visible text, a translation changes the id.
Without AnvilProvider or TrackingProvider, generated ids use the scope ST.
Pass data-tracking-id to supply your own value. Anvil2 skips generation for that element and keeps the value you passed.
Opt out when the product already tracks with its own ids. Set trackingIdData on AnvilProvider.
trackingIdData.scope is the prefix on generated ids. It defaults to ST. TrackingProvider accepts the same scope and optOut when the tree is not wrapped in AnvilProvider.
Opt-out skips later lookups. An id already written on that element stays until the component mounts again.