A product tour script runs inside your app, so three things can go wrong. Your CSS can leak into the tour and make it look broken. The tour's CSS can leak into your app and change your buttons. Or your Content Security Policy can block the tour's styles entirely, so tooltips show up as unstyled text. Ask any vendor how they handle all three before you install their snippet. Here is how we handle them in Cueston, so you know what a good answer sounds like.
Problem 1: your CSS leaks into the tour
If tooltips are added as regular elements on your page, every global rule you have applies to them: a reset that removes button padding, a "p { margin-bottom: 2rem }", a font set on everything. The tooltip looks different on every page and you end up writing CSS overrides for a third-party tool.
The fix is a Shadow DOM. Styles outside a shadow root don't reach inside it, and styles inside don't reach out. Cueston renders every tooltip, banner and tour step inside a closed shadow root attached to a single container element. Closed means your page's scripts can't reach into it by accident either.
Problem 2: the tour's CSS leaks into your app
The reverse problem is worse, because you might not notice it for weeks. A tour library that ships a global stylesheet with a rule like ".button" or "h3" will restyle matching elements in your app. With a Shadow DOM, this can't happen: the tour's styles only apply inside its own root.
Problem 3: CSP blocks the tour's styles
Many security-conscious apps set a Content Security Policy where style-src has no 'unsafe-inline'. That blocks every <style> element without the right nonce. Plenty of onboarding tools quietly assume 'unsafe-inline' is allowed, and their tooltips render as plain, unstyled text on strict sites. Some ask you to loosen your CSP, which your security team should refuse.
The right approach is to reuse your nonce. Cueston's scripts read the nonce from the <script> tag that loaded them and put it on every <style> element they create. Add the nonce to the Cueston snippet like you do for your own scripts, and the guidance stays styled without any CSP changes.
Two smaller things that also break tours
- Blocking your clicks. An overlay that covers the page can swallow clicks meant for your app. Our container is a full-viewport layer with pointer-events turned off; only the tooltip itself accepts clicks.
- Wrong position inside transformed containers. Elements inside a parent with a CSS transform (common in modals, drawers and scaled previews) don't position like the rest of the page. We detect a transformed ancestor and position relative to it, including its scale.
Elements that load late
In single-page apps, the button a tour step points at often doesn't exist yet when the step starts. A tour that checks once and gives up will skip steps or fail silently. We wait for the element with one shared MutationObserver, up to a timeout, and treat an invalid selector as "not found" instead of throwing an error into your page. A broken tour step should never break your app.
Questions to ask any vendor
- Do you render inside a Shadow DOM, and is it open or closed?
- Do you add global CSS to my page? Which selectors?
- Do you support a CSP nonce, or do you need 'unsafe-inline'?
- Does your overlay block clicks on my app?
- What happens when a step's target element isn't there yet, or the selector is invalid?
Frequently asked questions
Why does my product tour look different on different pages?▾
Usually because your app's global CSS applies to the tour's elements. Tools that render inside a Shadow DOM aren't affected by your page styles.
Do product tour tools work with a strict Content Security Policy?▾
Only if they support a nonce for their style and script tags. Cueston reads the nonce from its own script tag and applies it to every style it adds, so you don't need 'unsafe-inline'.
Can a product tour break my app?▾
A badly built one can: global CSS that restyles your elements, an overlay that blocks clicks, or an exception from an invalid selector. Ask the vendor how they prevent each one.