Long Press

Touch-and-hold interaction.

Hold to delete — ring fills over 600ms of holding, released early

html

<div class="rsp-lp-stage">
  <button type="button" class="rsp-lp-btn">
    <svg viewBox="0 0 44 44" width="44" height="44" aria-hidden="true">
      <circle cx="22" cy="22" r="18" fill="none" stroke="#24143022" stroke-width="4"/>
      <circle class="rsp-lp-ring" cx="22" cy="22" r="18" fill="none" stroke="#F5C2E0" stroke-width="4" stroke-dasharray="113.1" style="stroke-dashoffset:113.1; transform:rotate(-90deg); transform-origin:50% 50%;"/>
    </svg>
  </button>
  <p class="rsp-lp-caption">Hold to delete &mdash; ring fills over 600ms of holding, released early</p>
</div>
<style>
.rsp-lp-stage { width: 100%; max-width: 320px; padding: 18px; background: #FAF7F2; border: 1px solid #24143022; border-radius: 12px; font: 13px system-ui, sans-serif; color: #241430aa; text-align: center; }
.rsp-lp-btn { border: none; background: transparent; cursor: pointer; padding: 0; }
.rsp-lp-caption { margin: 12px 0 0; }
@media (prefers-reduced-motion: no-preference) {
  .rsp-lp-ring { transition: stroke-dashoffset 600ms linear; }
}
</style>

tailwind

<div class="w-full max-w-[320px] p-[18px] bg-[#FAF7F2] border border-[#24143022] rounded-xl font-sans text-sm text-[#241430]/70 text-center">
  <button type="button" class="border-0 bg-transparent cursor-pointer p-0">
    <svg viewBox="0 0 44 44" width="44" height="44" aria-hidden="true">
      <circle cx="22" cy="22" r="18" fill="none" stroke="#24143022" stroke-width="4"/>
      <circle class="tw-lp-ring" cx="22" cy="22" r="18" fill="none" stroke="#F5C2E0" stroke-width="4" stroke-dasharray="113.1" style="stroke-dashoffset:113.1; transform:rotate(-90deg); transform-origin:50% 50%;"/>
    </svg>
  </button>
  <p class="mt-3">Hold to delete &mdash; ring fills over 600ms of holding, released early</p>
</div>
<style>
@media (prefers-reduced-motion: no-preference) {
  .tw-lp-ring { transition: stroke-dashoffset 600ms linear; }
}
</style>

react

export function LongPress({
  held = false,
  duration = 600,
  label = "Hold to delete",
  accent = "#F5C2E0",
}) {
  return (
    <div style={{ width: "100%", maxWidth: 320, padding: 18, background: "#FAF7F2", border: "1px solid #24143022", borderRadius: 12, fontFamily: "system-ui, sans-serif", fontSize: 13, color: "#241430aa", textAlign: "center" }}>
      <button type="button" style={{ border: "none", background: "transparent", cursor: "pointer", padding: 0 }}>
        <svg viewBox="0 0 44 44" width="44" height="44" aria-hidden="true">
          <circle cx="22" cy="22" r="18" fill="none" stroke="#24143022" strokeWidth="4" />
          <circle className="ring" cx="22" cy="22" r="18" fill="none" stroke={accent} strokeWidth="4" strokeDasharray="113.1" style={{ strokeDashoffset: held ? 0 : 113.1, transform: "rotate(-90deg)", transformOrigin: "50% 50%" }} />
        </svg>
      </button>
      <p style={{ margin: "12px 0 0" }}>{label} &mdash; ring fills over {duration}ms of holding, {held ? "completed" : "released early"}</p>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          .ring { transition: stroke-dashoffset ${duration}ms linear; }
        }
      `}</style>
    </div>
  );
}