HP5002 (input-reset) means text a user typed, or a checkbox they checked,
before the page finished hydrating was cleared or replaced when React took
over. The user loses their input without a warning. Use uncontrolled inputs or
read the current DOM value on mount, and fix any hydration mismatch around the
form.
| Code | HP5002 |
|---|---|
| Name | input-reset |
| Default severity | Error |
| Group | Interaction during hydration |
| What it means | Text typed or an option chosen before hydration finished was cleared or replaced. |
What the HP5002 input reset finding means
The finding comes from the interaction checks
(checks.interactions: true or --interactions). hydration-proof loads the
page with its scripts held back, like a user on a slow connection, types
hydration-proof check into the first text field and checks the first
checkbox. Then it lets the page hydrate and reads the controls again:
Text typed into this field before the page finished hydrating was cleared.
A checkbox checked before the page finished hydrating was unchecked by hydration.When React replaced the field itself, the finding adds: "React replaced the field during hydration, so the new field lost what was typed." It is an error, because the user's work is gone.
Likely causes
- A hydration mismatch in the form or around it. React throws away that branch and renders it again, with new, empty inputs; the finding usually sits next to HP1010 or HP1011.
- An effect that sets the value on mount, such as restoring a saved draft or a value from the URL.
- Controlled inputs whose state is reset by a re-render during hydration.
- Server Action form state that the client hydrates without.
How to fix it
- Fix any hydration mismatch around the form. A re-rendered branch creates new, empty inputs, so this comes first.
- Use uncontrolled inputs (
defaultValue,defaultChecked). The browser keeps what was typed, and React hydrates the field as it is. - Or read the current DOM value when the component mounts, so text typed before hydration is kept in state.
An effect that overwrites the field:
"use client";
import { useEffect, useState } from "react";
// Before: restoring the last query replaces what the user typed
export function Search() {
const [query, setQuery] = useState("");
useEffect(() => {
setQuery(sessionStorage.getItem("last-query") ?? "");
}, []);
return (
<input value={query} onChange={(event) => setQuery(event.target.value)} />
);
}"use client";
import { useEffect, useRef, useState } from "react";
// After: what the user already typed wins over the saved value
export function Search() {
const inputRef = useRef<HTMLInputElement>(null);
const [query, setQuery] = useState("");
useEffect(() => {
const typed = inputRef.current?.value ?? "";
setQuery(
typed !== "" ? typed : (sessionStorage.getItem("last-query") ?? "")
);
}, []);
return (
<input
ref={inputRef}
value={query}
onChange={(event) => setQuery(event.target.value)}
/>
);
}An uncontrolled field needs none of this:
export function Newsletter() {
return (
<form action="/subscribe" method="post">
<input name="email" type="email" defaultValue="" />
<label>
<input name="weekly" type="checkbox" defaultChecked={false} /> Weekly
</label>
<button type="submit">Subscribe</button>
</form>
);
}When it is acceptable
A field that should reset on load (a one-time code, for example) can be
ignored with an ignore.issues rule for code: "HP5002", its route and a
reason; see ignoring findings.