Skip to main content

Prevent dialogs from hijacking LCP

Make dialogs smaller than main content or delay them until user interaction to prevent them from becoming the Largest Contentful Paint (LCP) element.


JavaScript injects most dialogs and banners into the page after the initial HTML has loaded. Because they aren't in the initial HTML, the browser discovers them late in the page load process. If the dialog is the largest single element in the viewport when it appears, then it becomes the LCP element. This resets the LCP clock: the browser reports the dialog's appearance time as the LCP value, rather than the time the user first saw the main content.

The result is that LCP no longer reflects the user's actual loading experience. A page that renders its hero image in 1.5 seconds might report an LCP of 4 seconds because a cookie banner appeared at that point and was larger than the hero. This affects your Core Web Vitals field data and can push LCP from Good into Needs Improvement or Poor territory.


Anchor to Size dialogs smaller than the main contentSize dialogs smaller than the main content

The simplest fix is to make the dialog smaller than the true LCP element. The browser selects the largest visible element in the viewport as LCP. If your hero image or heading is larger than the dialog, then the dialog won't take over as the LCP element.

Reduce the dialog's visual footprint:

  • Use a narrow banner bar instead of a full-screen overlay.
  • Keep dialog text size smaller than the main heading.
  • Limit dialog height so it doesn't dominate the viewport.

Anchor to Delay dialogs until user interactionDelay dialogs until user interaction

Defer dialog display until after the user has engaged with the page. This prevents the dialog from appearing during the LCP measurement window. LCP measurement finalizes on the first scroll as well as on the first input, that is, a click, tap, or keypress, so a dialog that appears only after one of those can't become the LCP element.

Gate the dialog on interaction, not on a timer. A dialog shown by a bare setTimeout on a page the user hasn't touched is still LCP-eligible, and if it's larger than your hero, then it becomes a later, worse LCP candidate:

// Delay the popup until the user scrolls, clicks, taps, or types
function showPopup() {
var popup = document.getElementById('promo-popup');
if (popup) {
popup.removeAttribute('hidden');
}
}

var popupShown = false;

function triggerPopup() {
if (popupShown) return;
popupShown = true;
showPopup();
}

['scroll', 'pointerdown', 'keydown'].forEach(function (eventType) {
window.addEventListener(eventType, triggerPopup, { once: true, passive: true });
});

Anchor to Control dialog rendering with LiquidControl dialog rendering with Liquid

For dialogs rendered server-side, use Liquid to control which pages show the dialog. This avoids loading dialog markup and styles on pages where the dialog isn't needed:

{%- comment -%}
Render the email signup popup only on index and collection pages.
Skip it on product and cart pages, where it interrupts the purchase flow.
{%- endcomment -%}
{% if template.name == 'index' or template.name == 'collection' %}
<div id="email-popup" hidden class="popup-overlay">
<div class="popup-content">
<button class="popup-close" aria-label="Close">&times;</button>
<h2>{{ section.settings.popup_heading }}</h2>
<p>{{ section.settings.popup_text }}</p>
{% form 'customer' %}
<input type="email" name="contact[email]" placeholder="Your email" required>
<button type="submit">Subscribe</button>
{% endform %}
</div>
</div>
{% endif %}

Anchor to You can't opt an element out of LCPYou can't opt an element out of LCP

There's no attribute or API that removes an element from Largest Contentful Paint candidacy. The Largest Contentful Paint specification notes that, unlike Element Timing, elements don't need to be annotated to become eligible, and the algorithm never reads an opt-out signal.

In particular, elementtiming doesn't do this. That attribute opts an element into the Element Timing API so you can measure when it renders. It has no effect on your LCP score.

The only reliable fixes are to keep the dialog smaller than your real LCP element, or to not render it until the user has interacted with the page.

Anchor to Remove the dialog if possibleRemove the dialog if possible

Email capture dialogs that appear before the user has seen any content are a UX anti-pattern. The user hasn't had a chance to evaluate the site, so conversion rates are typically low. Consider less intrusive alternatives:

  • Inline email signup forms within the page content.
  • A non-modal banner at the top or bottom of the page.
  • A signup prompt after the user has viewed several pages.

Anchor to Before: the dialog becomes the LCP elementBefore: the dialog becomes the LCP element

In Chrome DevTools, open the Performance panel, record a page load, and look at the Timings track. The LCP marker identifies which element the browser selected. If it points to your dialog or banner overlay, then the dialog has taken over LCP.

You can also use the Insights tab in the Performance panel, which automatically highlights the LCP element and flags issues. If the LCP element is a dialog, then the tab shows it.

Anchor to After: the dialog is deferred past LCPAfter: the dialog is deferred past LCP

After adding the interaction gate from the code example above:

  1. Record a new page load in the Performance panel.
  2. The LCP marker now points to your hero image or main heading.
  3. The dialog appears later in the timeline, after the user's first scroll or input.

The reported LCP now reflects the actual content loading time.


  • Open the Insights tab in the Chrome DevTools Performance panel. It automatically identifies the LCP element on page load. If the LCP element is a dialog or banner, then you have the problem described here.
  • Open the Performance panel, record a page load, and look for the LCP marker in the Timings track. Hover over it to see which element was selected.
  • After applying a fix, record another page load and confirm that the LCP element is now your main content, such as a hero image, heading, or featured text.
  • Test with both mobile and desktop viewports. A dialog that's smaller than the hero on desktop might be larger than the hero on a narrow mobile viewport.


Was this page helpful?