Skip to content

Latest commit

 

History

History
199 lines (157 loc) · 5.2 KB

File metadata and controls

199 lines (157 loc) · 5.2 KB
layout page
title INP Simulator
page-class page--inp-simulator
meta A small interactive demo for simulating sluggish interactions and delayed feedback when exploring INP.
permalink /inp-simulator/
lux INP Simulator

INP, or Interaction to Next Paint, is one of Google’s three Core Web Vitals: a measure of how responsive your site feels once someone actually starts using it. Poor INP scores are a sure sign of user frustration. This simulator allows you to experience the same kinds of delays that your users are feeling.

If your site feels sticky, sluggish, or slow to react, this is exactly the sort of problem I help teams diagnose and fix. Let’s talk!

<style> .c-inp-simulator-controls { padding: 24px; background-color: #fff; border: 1px solid #ddd; border-radius: 3px; margin-bottom: 24px; } .c-inp-simulator-controls > :last-child { margin-bottom: 0; } .c-inp-simulator-slider { width: 100%; accent-color: #f43059; } .c-inp-simulator-delay { font-variant-numeric: tabular-nums; font-weight: 600; } .c-inp-simulator-delay-rating--good { color: #09ce6b; } .c-inp-simulator-delay-rating--needs-improvement { color: #ffa400; } .c-inp-simulator-delay-rating--poor { color: #ff4e42; } .c-inp-simulator-toggle { margin-bottom: 24px; } .c-inp-simulator-panel { padding: 24px; border: 1px solid #f43059; border-radius: 3px; background-color: #fff; } .c-inp-simulator-panel > :last-child { margin-bottom: 0; } .c-inp-simulator-panel[hidden] { display: none; } .c-inp-simulator-input { width: 100%; min-height: 7.5rem; resize: vertical; } .c-inp-simulator-output { min-height: 1.5em; margin-bottom: 0; color: #666; } </style>

Delay amount: 200ms – Needs Improvement

Click me…

Start typing… <textarea class="c-input-text c-inp-simulator-input" id="jsInpInput" rows="4" cols="50" placeholder="Type here…"></textarea>

Mirrored output:

<script> (() => { const clampDelay = (value) => Math.max(0, Math.min(1500, Number.parseInt(value, 10) || 0)); function longTask(ms) { const start = Date.now(); while (Date.now() - start <= ms) { true; } } const delayInput = document.getElementById('jsInpDelay'); const delayValue = document.getElementById('jsInpDelayValue'); const delayRating = document.getElementById('jsInpDelayRating'); const toggle = document.getElementById('jsInpToggle'); const panel = document.getElementById('jsInpPanel'); const input = document.getElementById('jsInpInput'); const output = document.getElementById('jsInpOutput'); if (!delayInput || !delayValue || !delayRating || !toggle || !panel || !input || !output) return; let delay = clampDelay(delayInput.value); let timeoutId; const renderDelay = () => { let rating = 'Good'; let ratingClass = 'c-inp-simulator-delay-rating--good'; if (delay === 404) { rating = 'Interaction Not Found'; ratingClass = 'c-inp-simulator-delay-rating--needs-improvement'; } else if (delay > 500) { rating = 'Poor'; ratingClass = 'c-inp-simulator-delay-rating--poor'; } else if (delay >= 201) { rating = 'Needs Improvement'; ratingClass = 'c-inp-simulator-delay-rating--needs-improvement'; } delayValue.textContent = delay; delayRating.textContent = rating; delayRating.className = ratingClass; }; renderDelay(); // Allow folk to hot-link a specific delay const urlParams = new URLSearchParams(window.location.search); const delayParam = urlParams.get('delay'); if (delayParam !== null) { delay = clampDelay(delayParam); delayInput.value = delay; renderDelay(); } delayInput.addEventListener('input', () => { delay = clampDelay(delayInput.value); renderDelay(); }); toggle.addEventListener('click', () => { panel.hidden = !panel.hidden; toggle.setAttribute('aria-expanded', String(!panel.hidden)); longTask(delay); if (!panel.hidden) { input.focus(); } }); input.addEventListener('input', () => { clearTimeout(timeoutId); const inputValue = input.value; timeoutId = window.setTimeout(() => { output.textContent = inputValue; }, delay); }); })(); </script>