Skip to content

Known Issues: @click.self and Click Event Handling ​

Last updated: 2026-04-27

Background ​

PR #716 ("Analytics fixes", McSneaky, merged into v6.8.2) changed multiple click handlers from @click to @click.self and removed .stop modifiers across the codebase. The intent was to make background clicks opt-in instead of opt-out, avoiding unintended bg click triggers from child elements.

This introduced two bugs that are still present in production (v6.8.5).

Bug 1: Clickable Background Broken by Visual Elements ​

Status: Broken since v6.8.2. Reported by Gediminas 2026-04-27.

What: Creatives with clickable background enabled no longer click through when a visual element (graphic, text, HTML block) covers the background area.

Root cause: CreativeBody.vue line 16 uses @click.self="handleBgClick". The .self modifier only fires when event.target === event.currentTarget (the body element itself). When a graphic block sits on top of the body, the click target is the graphic element, not the body, so .self never matches and handleBgClick never runs.

Before PR #716: @click="handleBgClick" -- clicks from child elements bubbled up and triggered handleBgClick. Visual elements didn't block background clicks.

After PR #716: @click.self="handleBgClick" -- only direct clicks on the body element itself trigger handleBgClick. Any child element absorbs the click.

Workaround: Add pointer-events: none in Custom CSS on the graphic block. This lets clicks pass through to the body.

Previous fix attempts:

  • PR #692 ("Fix blocks blocking bg click") -- added dynamic pointer-events based on hasClickthrough. This was before PR #716 changed to .self.
  • PR #711 ("Fix hover on visual elements") -- reverted #692 because pointer-events: none broke hover animations on visual elements. Set all visual elements back to pointer-events: auto.

Why PR #692/#711 are no longer the core issue: Those PRs tried to fix clickthrough by toggling pointer-events on visual elements. But the real problem is now @click.self on CreativeBody (introduced later in PR #716). Even with pointer-events: auto on visual elements, if CreativeBody used @click instead of @click.self, clicks would bubble through and trigger handleBgClick.

Bug 2: clicks Counter Effectively Always Zero ​

Status: Broken since v6.8.2. Not yet reported externally.

What: The clicks Bunny metric (raw click count on the creative) is almost never incremented.

Root cause: Creative.vue line 16 uses @click.self="creativeContainerClicked". CreativeBody covers the entire #creative-container, so event.target is never the container itself. The .self modifier prevents the handler from firing.

Impact: clicks in Bunny analytics is near-zero for all creatives. This was the "broadest click metric" intended to count every click anywhere. Currently useless.

Note: creativeClickedOnce (first interaction) was fixed in PR #735 by adding a separate @click.capture="handleFirstInteraction" handler. But clicks++ was left inside the .self handler and remains broken.

PR History ​

PRWhatEffect
#692Dynamic pointer-events on visual elementsFixed bg click passthrough, but broke hover animations
#711Reverted #692, back to pointer-events: autoRestored hover, bg click still worked (pre-#716)
#716Changed @click to @click.self on CreativeBody and Creative.vue, removed .stop modifiersBroke clickable background AND clicks counter
#735Added @click.capture for creativeClickedOnceFixed first-interaction detection, but clicks still broken

The .self Debate (PR #716 Review) ​

In the PR #716 review, Nicolay proposed using capture-phase counting instead of removing .stop everywhere:

js
// Capture phase listener fires before any .stop can block it
this.$el.addEventListener('click', (e) => {
  if (!e.isTrusted) return
  Analytics.clicks++
}, { capture: true })

Kevin went with .self instead, dismissing concerns from both Nicolay and Copilot about bubbling issues with "Nope, doesn't cause issues" / "Nope, no double data". He tested with creatives where visual elements didn't fully cover the background, so the issues weren't visible.

In PR #735 review (2026-04-23), Kevin acknowledged the .self issue for the clicks counter: "I didn't notice anything broken with current click.self, but now when you point it out, it might be good to test it over again."

Proposed Fixes ​

clicks counter (same fix regardless of approach) ​

Move clicks++ to a capture-phase handler, same pattern as handleFirstInteraction in PR #735:

js
@click.capture="handleAnyClick"

handleAnyClick(event: MouseEvent) {
  if (!event.isTrusted) return
  Analytics.clicks++
}

Counts every real click regardless of .stop or .self. Kevin already approved this pattern in PR #735.

Clickable background: three approaches ​

Approach A: Remove .self, use .stop on interactive elements ​

Revert CreativeBody to @click="handleBgClick". Clicks bubble naturally. Visual elements without clickthrough do nothing in handleClick(), so the click bubbles to body and triggers bg click. Visual elements WITH clickthrough call event.stopPropagation() to prevent double-firing. Interactive elements (choices, form, close button, etc.) get .stop back.

js
// VisualElementMixin.ts
handleClick(event: MouseEvent): void {
  if (!this.clickthroughUrl) return   // bubbles to handleBgClick
  event.stopPropagation()              // has own clickthrough, block bg click
  this.trackClick()
}
html
<!-- CreativeBody.vue -->
@click="handleBgClick"

<!-- Interactive elements get .stop back -->
<Choice @click.stop="..." />
<FormSubmitButton @click.stop="..." />
SummaryStandard DOM event model. Clicks bubble up by default, interactive elements opt out with .stop.
ProsCorrect event model. No pointer-events hacks. Hover animations preserved. Visual elements just work -- no special wiring needed.
ConsKevin opposed this in PR #716 ("devs must remember .stop"). New interactive components must add .stop or they trigger bg click.
ComplexitySmall: revert .self, restore .stop on ~6 interactive components, add event param to handleClick.
RiskLow. This is how it worked before PR #716. The .stop list is known and stable.

Approach B: Keep .self, emit bgClick from visual elements ​

Keep Kevin's .self on CreativeBody. Visual elements without clickthrough manually emit bgClick upward. CreativeBody already listens for @bg-click on conversation, video, and form blocks -- extend this to visual elements.

js
// VisualElementMixin.ts
handleClick(): void {
  if (this.clickthroughUrl) {
    this.trackClick()
    return
  }
  this.$parent?.$emit('bgClick')
}
html
<!-- CreativeBody.vue: add @bg-click to visual element templates -->
<CreativeGraphicBlock @bg-click="handleBgClick" ... />
<CreativeTextBlock @bg-click="handleBgClick" ... />
SummaryWorks within .self constraint. Visual elements explicitly forward clicks to bg handler via $emit, same pattern conversation/video/form already use.
ProsNo changes to .self or .stop. Kevin's model stays intact. Hover animations preserved. Consistent with existing @bg-click pattern already used by 3 block types.
ConsRequires adding @bg-click listeners in CreativeBody for visual element types. Slightly more wiring than Approach A.
ComplexitySmall-medium: modify handleClick to $emit('bgClick'), add @bg-click="handleBgClick" on graphic/text/HTML blocks in CreativeBody template.
RiskLow. Uses the same $emit/@bg-click pattern that conversation, video, and form blocks already use successfully.

Approach C: Keep .self, dynamic pointer-events ​

Keep .self. Make visual elements set pointer-events: none when bg click is enabled and they have no own clickthrough. Clicks pass through to body, .self matches.

js
// In visual element styles() computed
'pointerEvents': (DataStore.creativeSettings.creativeDelivery.backgroundClickthrough
  && !this.clickthroughUrl) ? 'none' : 'auto'
SummaryCSS-level fix. Visual elements become transparent to clicks when bg click is active.
ProsDeclarative. No event forwarding. Works with .self.
ConsBreaks hover animations and CSS :hover states (tried and reverted in PR #692/#711). Users must use custom CSS for hover effects on affected elements.
ComplexitySmall: add one computed check to each visual element's styles.
RiskHigh. Already tried and reverted once. Hover is a real feature people use.

Recommendation ​

Both A and B are good options with low risk.

Approach A uses standard DOM semantics and is the simplest mental model -- clicks bubble unless stopped. It was the working model before PR #716.

Approach B works within the existing .self model and extends a pattern already established for conversation, video, and form blocks. No need to revert Kevin's changes.

Approach C should be avoided -- it was already tried and reverted due to broken hover animations.

Key Files ​

FileRole
Creative-Engine/src/components/creative/Creative.vueContainer click handlers (@click.self, @click.capture)
Creative-Engine/src/components/conversationflow/CreativeBody.vueBackground click handler (@click.self="handleBgClick")
Creative-Engine/src/mixins/VisualElementMixin.tsVisual element click handler (handleClick)
Creative-Engine/src/components/creative/VisualElements/CreativeGraphicBlock.vueGraphic block with pointerEvents: 'auto'
Creative-Engine/src/components/creative/VisualElements/CreativeTextBlock.vueSame pattern
Creative-Engine/src/components/creative/VisualElements/CreativeHtmlBlock.vueSame pattern

Internal documentation