HP5006 (double-handler) means an element has a React event handler and, for
the same event, a listener added by a script or an inline on* attribute. One
click, submit or key press can then run two actions: a double submit, a double
tracking event. Handle the event in one place.
| Code | HP5006 |
|---|---|
| Name | double-handler |
| Default severity | Warning |
| Group | Interaction during hydration |
| What it means | A script or an inline handler attribute handles an event on an element that React also handles, so one action can run twice. |
What the HP5006 double handler finding means
React handles events at the root of the app. A listener added directly to the
element with addEventListener, or an onclick attribute in the HTML, runs in
addition to it. hydration-proof records the listeners page scripts add to
elements and compares them with the React props of each element during
hydration:
React handles "click" on this element, and so does a script listener or an inline onclick attribute. One action can run twice.The events it tracks are click, submit, input, change, keydown and
keyup. The check is part of the props audit (checks.propsAudit, on by
default), so it runs on every page without --interactions. It is a warning,
and it is not reported on elements marked with suppressHydrationWarning.
Likely causes
- An analytics or tag manager script that attaches click listeners to buttons and links.
- An older script, such as a jQuery plugin, that enhances the same form React renders.
- Server HTML post-processed to add
onclickoronsubmitattributes. - A script that changes the page before hydration and adds handlers while it does.
How to fix it
Handle the event in one place: remove the inline on* attribute or the script
that adds the listener, or remove the React handler.
When the extra listener only tracks the click, call the tracking code from the React handler and stop the script from attaching its own:
import { track } from "@/lib/analytics";
export function BuyButton({ onBuy }: { onBuy: () => void }) {
return (
<button
type="button"
onClick={() => {
track("buy");
onBuy();
}}
>
Buy
</button>
);
}If the script must stay, check that the two handlers do different things and that neither submits or navigates twice.
When it is intentional
If both handlers are meant to run, add an ignore.issues rule with
code: "HP5006", the element's selector and a reason; see
ignoring findings.