# HP5002: User input was reset during hydration

> HP5002 (input-reset) means text typed or a box checked before hydration finished was cleared or replaced. Keep what users type with uncontrolled inputs.

Source: https://hydration.jscrate.dev/docs/issues/hp5002
Last updated: 2026-09-18

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](https://hydration.jscrate.dev/docs/interactions)
(`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
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](https://hydration.jscrate.dev/docs/issues/hp1010) or [HP1011](https://hydration.jscrate.dev/docs/issues/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](https://hydration.jscrate.dev/docs/causes/form-state) that the client hydrates
  without.

## How to fix it

1. **Fix any hydration mismatch around the form.** A re-rendered branch creates
   new, empty inputs, so this comes first.
2. **Use uncontrolled inputs** (`defaultValue`, `defaultChecked`). The browser
   keeps what was typed, and React hydrates the field as it is.
3. **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:

```tsx title="components/search.tsx"
"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)} />
  );
}
```

```tsx title="components/search.tsx"
"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:

```tsx title="components/newsletter.tsx"
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](https://hydration.jscrate.dev/docs/ignoring).

## Related

- [HP5003: focus was lost during hydration](https://hydration.jscrate.dev/docs/issues/hp5003)
- [HP5001: a click before hydration was lost](https://hydration.jscrate.dev/docs/issues/hp5001)
- [HP1012: form state differs between server and client](https://hydration.jscrate.dev/docs/issues/hp1012)
- [Interaction checks](https://hydration.jscrate.dev/docs/interactions)
- [HP1010: React rendered a branch again](https://hydration.jscrate.dev/docs/issues/hp1010)
