Home / Articles / Website Performance
Website Performance

Button Feels Stuck? How to Read and Fix INP on Your Website

A website may appear fully loaded, but still feel slow when users open menus, submit forms, or press buttons. INP helps identify that issue—and the fix often starts with JavaSc...

Tombol Terasa Macet? Cara Membaca dan Memperbaiki INP di Website

A fast website is not just one that displays pages immediately. Users also expect buttons to respond instantly, menus to be smooth, and visual changes to appear without disruptive delays. This is why Interaction to Next Paint or INP is important: this metric measures how quickly a page responds to user interactions during a visit, not just when the page is first opened.

INP is one of the Core Web Vitals. A good INP score is considered to be 200 milliseconds or less, while above 500 milliseconds falls into the poor category. The assessment is usually viewed at the 75th percentile, separated between mobile and desktop devices. In other words, the goal is not to make one developer's device feel fast, but to ensure that the majority of users receive a good response.

The problem is often not visible from the initial speed score. A page can display the main content quickly, but the search button, product filters, modals, or new forms may respond after several hundred milliseconds. For users, this experience feels like the button is stuck.

What does INP measure in interactions?

Each interaction has three main parts. First, input delay, which is the time before the interaction handling code starts running. Second, processing duration, which is the time taken by JavaScript to perform tasks after a click or touch is received. Third, presentation delay, which is the time until the browser displays the next frame showing the results of the interaction.

For example, when a user presses the “Show Filter” button, the browser may be running other heavy JavaScript, causing the click to wait. After that, the button code opens the panel, recalculates the product list, and changes many HTML elements. If all the work is done in one long sequence, the browser hasn't had a chance to render the changes on the screen. The user sees the button pressed, but the panel appears later.

According to web.dev documentation, INP accounts for the entire delay and observes interactions throughout the page's lifecycle. Therefore, speeding up the initial display alone does not necessarily solve the responsiveness issue.

Why is JavaScript often the culprit?

The browser has a main thread, the primary workflow that handles many important tasks such as processing JavaScript, calculating layouts, and preparing displays. If this thread is busy working on long tasks, user interactions must wait.

Common causes include:

  • JavaScript files are too large and must be processed when the page starts being used.
  • Event handlers are doing too much work at once.
  • Large DOM changes after user interactions.
  • Code reads element sizes after changing styles in the same task, triggering synchronous layout recalculations.
  • Repeating timers like setInterval() running heavy tasks while users are trying to interact.

This is why adding server CPU or installing new caches does not always fix INP. Caching helps reduce page delivery time, but does not automatically make JavaScript in the browser lighter.

How to find the slowest interactions

Don't start by guessing. First, identify the interactions that are most problematic and measure which parts take the longest.

  1. Check real user data. Use Core Web Vitals reports, PageSpeed Insights, or measurements based on web-vitals to see if the issues primarily occur on mobile or desktop. Field data helps show the actual device and network conditions used by visitors.
  2. Reproduce the issue in Chrome DevTools. Open the Performance panel, start recording, then perform actions like opening menus, using filters, or submitting forms. Pay attention to long tasks, scripting activity, and sections marked Layout or Recalculate Style.
  3. Test meaningful interactions. Don't just test the homepage. Product detail pages, searches, dashboards, checkouts, and editors usually have heavier interactions.
  4. Compare devices. Interactions that feel fast on a developer's laptop may be slow on a mid-range phone. Simulate limited CPU and network conditions for more realistic testing results.

Practical fixes to try

1. Only do what's needed for the next frame

When a user clicks a button, prioritize visual changes that need to be seen immediately. Other tasks—like logging, calculating statistics, or updating secondary elements—can be scheduled after the main view changes.

button.addEventListener('click', () => {
  panel.classList.add('is-open');

  requestAnimationFrame(() => {
    setTimeout(() => {
      saveActivityLog();
      updateAdditionalData();
    }, 0);
  });
});

This pattern is not a one-size-fits-all solution. Use it carefully, especially if the deferred work is actually needed before the user can proceed.

2. Break large tasks into smaller ones

If an event handler needs to process a lot of data, don't force all the work to complete in one long task. Break the work into smaller parts so the browser has a chance to process other inputs and render the view.

For a long product list, for example, display the initial results first and then process the next parts gradually. For large applications, consider list virtualization, which only renders items currently visible on the screen.

3. Avoid repeated layout read-write patterns

A common issue is code changing styles and then immediately reading element sizes, followed by changing styles again. This pattern can force the browser to recalculate layouts multiple times. Group size readings first, then make visual changes afterward.

Check code that frequently uses properties like offsetWidth, offsetHeight, or getBoundingClientRect() between class and style changes. Not all uses of these properties are problematic, but repeated read-write sequences should be scrutinized.

4. Reduce work when the page becomes active

A page that has already displayed content may not be done working. JavaScript can still be parsed, compiled, and executed after the initial view appears. If users click buttons while the startup process is still ongoing, input delay can increase.

Start by removing unnecessary code on that page. After that, use bundle splitting by page or feature, defer modules that are not yet needed, and reevaluate third-party scripts that run automatically.

What does this mean for website owners?

INP is not just a number for technical reports. It indicates whether a website feels ready for interaction. An online store with slow filters can cause users to stop searching for products. A form that responds late can make people click buttons multiple times. A sluggish dashboard makes work feel heavier than it should.

Prioritizing fixes should follow the business flow. Look for interactions that are closest to user registration, searching, purchasing, or main tasks. After that, measure again with field data—not just a single test on a laptop.

What you can do now

  • Note the three most important interactions on your website.
  • Test all three on mobile devices with limited CPU.
  • Use DevTools Performance to look for long tasks.
  • Separate urgent visual work from additional tasks.
  • Measure INP again after each change, not after ten changes at once.

A responsive website does not always require a new architecture. Often, significant results come from small decisions: removing unnecessary work, rendering fewer elements, and giving the browser a chance to render changes faster.

Technical references: INP optimization guide on web.dev, Web Vitals documentation, and Chrome UX Report metrics methodology.

Sources & further reading

Explore also

– Rio Yotto @rioyotto