Qaid
ARTICLE

Element Targeting: Pinpoint Feedback on Any Element

Let users click on specific page elements to attach feedback directly to buttons, forms, or any UI component.

Qaid Team

"The button doesn't work" leaves you guessing which button. Element targeting has the reader point at it, and the submission arrives carrying a CSS selector and the element's own text.

What happens after a thumbs click

Targeting mode starts. Your page dims, crosshairs follow the cursor, and whatever sits under them highlights so there is no doubt about what a click will pick.

The click captures three things: a CSS selector that finds the element again, its visible text cut to 100 characters, and any data-comp, data-qa, data-testid or data-id attribute it carries.

All three travel with the feedback.

What the reader sees

Horizontal and vertical lines track the cursor with a circular scope where they cross, which is how somebody knows the page is waiting for a pick rather than broken.

Each element outlines as the cursor passes over it, green for a thumbs-up and red for a thumbs-down, so the reader can still see which way they voted.

The edges of the page darken slightly to pull attention inward.

After the click a marker sits on the chosen element while the modal opens, confirming what was caught.

How the selector gets built

Three strategies, in order, stopping at the first that works.

Data attributes win

If the element or any ancestor carries one, that is the selector:

<button data-testid="submit-payment">Pay Now</button>
<!-- Generates: [data-testid="submit-payment"] -->

It looks for data-comp first, then data-qa, data-testid and data-id.

Then the id

With no data attribute and an id present:

<form id="checkout-form">...</form>
<!-- Generates: #checkout-form -->

Special characters in the id get escaped.

Otherwise, a path

With neither, it counts its way down from body:

<body>
  <main>
    <div>
      <button>Click Me</button>  <!-- Third button in this div -->
    </div>
  </main>
</body>
<!-- Generates: body > main:nth-child(1) > div:nth-child(1) > button:nth-child(3) -->

That is unique today and wrong the moment somebody inserts a <div> above it. Which is the argument for the next section.

Label the elements you care about

Put a data attribute on anything you would want to hear about:

<!-- Before: Hard to identify -->
<button class="btn btn-primary">Submit</button>

<!-- After: Clear identification -->
<button class="btn btn-primary" data-testid="contact-form-submit">Submit</button>

Class names change every time somebody tidies the CSS; these do not. The value says what the element is for, so the selector reads as English in your inbox. Playwright and Cypress already use the same attributes, so you are probably half done. And you can search the inbox by attribute value.

Reading it in the dashboard

The selector sits in the feedback details, ready to paste into a search across your source.

The element text tells you what the reader was looking at without opening the page yourself.

A captured data attribute shows as a badge, which is what makes a long inbox scannable.

Filtering by selector pattern pulls up everything aimed at one component. Search checkout and you get every report about the checkout, whichever page it came from.

Turning it off

One flag skips the whole step:

<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
  data-skip-targeting="true"
></script>

Or in JavaScript:

import { QaidFeedback } from '@qaiddev/thumbs-embed';

new QaidFeedback({
  endpoint: '/api/feedback',
  skipTargeting: true
});

A thumbs click now opens the modal directly. You still get the page URL and the console errors, just nothing about which element.

Worth doing when the feedback is about a page rather than a thing on it, or when watching a real user hesitate at the crosshairs tells you the step is costing you more than it returns.

Styling the buttons that start it

Colors

marker is the colour of the ring around a selected element:

new QaidFeedback({
  endpoint: '/api/feedback',
  colors: {
    positive: '#22c55e',   // Green for thumbs up
    negative: '#ef4444',   // Red for thumbs down
    marker: '#6366f1'      // Purple outline on selected elements
  }
});

Button size

Three sizes:

new QaidFeedback({
  endpoint: '/api/feedback',
  buttonSize: 'small'   // 'small' | 'medium' | 'large'
});

Icons

Swap the thumbs for anything:

new QaidFeedback({
  endpoint: '/api/feedback',
  positiveIcon: '<svg>...</svg>',
  negativeIcon: '<svg>...</svg>'
});

Your own classes

Take over the styling:

new QaidFeedback({
  endpoint: '/api/feedback',
  buttonClass: 'my-custom-button'
});

With buttonClass set, the embed keeps only display and cursor and hands you the rest.

Position

Which corner they sit in:

new QaidFeedback({
  endpoint: '/api/feedback',
  position: 'bottom-left',  // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
  offset: { x: 24, y: 24 }  // Distance from screen edge
});

Getting out of targeting mode

Escape cancels at any point and returns everything to idle. Somebody who hit a thumb by accident is not trapped.

On a phone

Tap instead of click, and elements highlight on touch. The crosshair UI is the same. Below 640px the modal becomes a bottom sheet, which is what a phone user expects a panel to do.

Where to start

Add data-qa attributes to the twenty elements you would most want feedback on. Everything else falls out of that: readable selectors, a searchable inbox, and reports that land next to the code.

Back to all articles