> For the complete documentation index, see [llms.txt](https://help.usejimo.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.usejimo.com/docs/getting-started/create-your-first-experience/stable-selectors-on-a-dynamic-front-end.md).

# Stable selectors on a dynamic front-end

A tooltip, a hotspot or a progress trigger is attached to an element through a CSS selector. If that selector changes on the next page load, the step cannot find its element and the tour stops. This is the single most common reason a tour that worked in preview breaks a week later.

***

## How to tell if yours are stable

<figure><img src="https://2794860263-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKzAcDWQbK1gKbpra7bkb%2Fuploads%2Fj6sAbdZsAmOXSQ2JVT03%2Fn15-stable-selector.png?alt=media&#x26;token=0bba985d-1da7-4e93-9a87-992b6cd98f43" alt="A hashed class changes after a reload, a data-testid attribute stays the same"><figcaption><p>Same element, after a reload</p></figcaption></figure>

Open **Target element** on any attached step in the in-app builder. The selector sits under the element name. Reload your app and open the same step again: if the selector still matches, it is stable. Signs that it is not:

* Hashed class names: `css-1x2y3z`, `sc-bdVaJa`, `jss123`.
* Numbered IDs from a framework: `ember1061`, `:r3:`, `radix-:R1a:`.
* Attributes regenerated on every render, such as a `data-...-id` that changes when you reopen a menu.
* A selector that includes the element's text, in an app with several languages.

## What to ask your developer

One line, and it solves it for good: add a `data-testid` (or `data-jimo`) attribute with a fixed value on the elements you will target. A dozen elements for a first tour. Your front-end team may already have them for their own tests.

### Until then, in the builder

#### Reselect a stable parent

Click **Reselect** and choose a parent element that has a stable `id` or class, when the layout allows it.

#### Shorten the selector by hand

Edit the selector by hand to keep only the stable part. Jimo's picker shows the full chain; shortening it to one stable attribute is often enough.

#### Lower the match strictness

Lower the strictness of the match in the positioning options, so a minor change in the chain does not break it. See [Positioning](/docs/build/positioning.md).

## Selector patterns

The cheat sheet in [Targeting on dynamic apps](/docs/build/positioning/targeting-on-dynamic-apps.md) covers attribute selectors for partial matches (`[id^="menu-"]`, `[class*="primary-button"]`), single-page apps, and elements that appear after a delay. Read it with your developer before building the second tour.

## When the element is not on the page yet

A step attached to an element that renders after a click, or after data loads, needs the step before it to wait. Use the step's progress trigger on the user's action, not on the element's presence: a trigger keyed on an element that is already in the DOM fires immediately. See [Steps triggers](/docs/build/triggers-and-conditions/steps-triggers.md).

## Related

* [Positioning](/docs/build/positioning.md)
* [Targeting on dynamic apps](/docs/build/positioning/targeting-on-dynamic-apps.md)
* [Why my experience does not show](/docs/getting-started/publish-your-first-experience/why-my-experience-does-not-show.md)
