Skip to content

Element Selector

The element selector is the admin overlay tool that lets you target specific DOM elements on the host page for tours, tooltips, spotlights, and other content. It provides visual feedback about targeting reliability through a confidence scoring system.

Targeting Methods

Spotlight supports three methods for identifying DOM elements, evaluated in priority order:

PriorityMethodSelector FormatStability
1data-spotlight attribute[data-spotlight="dashboard-chart"]Highest
2Element ID#user-profile-btnHigh
3CSS selector.sidebar > nav > ul > li:nth-child(3)Variable

The ElementTarget value object enforces that at least one method is provided:

python
class ElementTarget(BaseModel):
    """Identifies a DOM element on the host page.

    At least one targeting method must be provided.
    Priority: data_attribute > element_id > css_selector.
    """

    data_attribute: str | None = None   # e.g. "dashboard-chart"
    element_id: str | None = None       # e.g. "user-profile-btn"
    css_selector: str | None = None     # e.g. ".sidebar > nav > li:nth-child(3)"
    description: str | None = None      # Human-readable label

The best_selector property returns the highest-priority selector available:

python
target = ElementTarget(data_attribute="dashboard-chart", element_id="chart-1")
target.best_selector
# => '[data-spotlight="dashboard-chart"]'

target = ElementTarget(element_id="chart-1")
target.best_selector
# => '#chart-1'

Using data-spotlight Attributes

The recommended approach is to add data-spotlight attributes to your application's HTML. These are stable across refactors since they are decoupled from structure and styling:

html
<!-- Recommended: explicit data-spotlight attributes -->
<button data-spotlight="create-project">New Project</button>

<div data-spotlight="dashboard-chart" id="revenue-chart">
  <!-- chart content -->
</div>

<nav data-spotlight="main-navigation">
  <ul>
    <li><a href="/dashboard">Dashboard</a></li>
    <li><a href="/projects">Projects</a></li>
  </ul>
</nav>

Benefits of data-spotlight:

  • Survives CSS class renames and structural refactors.
  • Communicates intent -- developers know which elements are targeted.
  • No collision with existing IDs or test attributes.
  • Can be scoped per feature: data-spotlight="onboarding.step-1".

Confidence Levels

When an admin selects an element in the overlay, the SDK evaluates targeting reliability and assigns a confidence level:

Green -- High Confidence

The element has a data-spotlight attribute or a stable id. These selectors will reliably resolve across page loads and deployments.

Target: [data-spotlight="create-project"]
Confidence: GREEN
Reason: Explicit data-spotlight attribute found

Yellow -- Medium Confidence

The element is identified by a CSS selector that is reasonably specific but depends on DOM structure. May break if the page layout changes.

Target: #app-container > .main-content > button.primary
Confidence: YELLOW
Reason: Structural CSS selector (3 levels deep)

Red -- Low Confidence

The element relies on fragile selectors such as deeply nested positional paths, auto-generated class names, or selectors that match multiple elements.

Target: div > div > div:nth-child(2) > span:nth-child(4)
Confidence: RED
Reason: Deeply nested positional selector (5+ levels)

Selector Health Monitoring

The backend tracks target_not_found events when the SDK cannot locate an element at runtime. The SelectorHealthService aggregates these failures into reports accessible from the admin panel:

python
report = await selector_health_service.get_health_report(
    tenant_id="tenant_abc",
    window_days=7,
    failure_threshold=3,  # only report selectors that failed 3+ times
)

# SelectorHealthReport(
#     tenant_id="tenant_abc",
#     total_failures=47,
#     unique_selectors=5,
#     broken_selectors=[
#         SelectorFailure(content_id="tour_123", failure_count=22, ...),
#         SelectorFailure(content_id="cnt_abc", failure_count=15, ...),
#         ...
#     ],
#     analysis_window_days=7,
# )

The admin API exposes this at GET /v1/admin/analytics/selector-health:

bash
curl -H "X-API-Key: sk_live_..." \
     -H "Authorization: Bearer <jwt>" \
     https://api.example.com/v1/admin/analytics/selector-health?window_days=7
json
{
  "tenant_id": "tenant_abc",
  "total_failures": 47,
  "unique_selectors": 5,
  "broken_selectors": [
    {
      "content_id": "tour_123",
      "content_type": "tour",
      "step_id": "step_3",
      "failure_count": 22,
      "url_path": "/dashboard",
      "last_failure_at": "2025-05-10T14:22:00Z"
    }
  ],
  "analysis_window_days": 7
}

The response is returned bare (no {"data": ...} envelope) on this endpoint. All other admin endpoints follow the envelope convention.

Interactive Selection Mode

When an admin activates the element selector from the toolbar (Ctrl+Shift+E), the overlay enters interactive selection mode:

  1. Hover highlight -- as the cursor moves, hovering elements are outlined with a dashed border.
  2. Click to select -- clicking an element captures its targeting information.
  3. Selector evaluation -- the SDK examines the element for data-spotlight, id, and generates a CSS selector fallback.
  4. Confidence display -- a badge shows the green/yellow/red confidence level.
  5. Refinement -- the admin can manually edit or override the generated selector.
  6. Test -- a "Test Selector" button runs document.querySelector() to verify the selector resolves to the intended element.

Best Practices

Add data-spotlight during development

The most reliable approach is to add data-spotlight attributes to key UI elements as part of your development workflow. Treat them like data-testid attributes -- stable anchors that are part of your application's contract.

Avoid auto-generated class names

CSS-in-JS libraries (Emotion, styled-components) and CSS Modules generate hashed class names that change between builds. Never use these as selectors.

Use the selector health dashboard

Review the selector health report weekly. A spike in target_not_found events after a deployment usually indicates a selector that needs updating.

Selector Priority Checklist

  1. Does the element have a data-spotlight attribute? Use it.
  2. Does the element have a stable, human-authored id? Use it.
  3. Is there a short, semantic CSS selector (e.g., nav.primary > .logo)? Acceptable, but monitor health.
  4. Would you need a path with 4+ structural levels? Add a data-spotlight attribute instead.

Spotlight