Ввод данных
Управляемое поле и доступная форма
Связываем текстовое поле с состоянием и сохраняем понятную подпись.
В управляемом поле value берётся из состояния, а onChange обновляет это состояние. Для текстового поля начальное значение удобно задавать пустой строкой, чтобы оно оставалось управляемым с первого рендера.
const [email, setEmail] = useState('');
<label htmlFor="email">Электронная почта</label>
<input
id="email"
name="email"
type="email"
autoComplete="email"
value={email}
onChange={event => setEmail(event.target.value)}
/>Подпись остаётся на экране
Placeholder исчезает при вводе и не заменяет label. Связь через htmlFor и id позволяет нажать на подпись для перехода в поле и помогает вспомогательным технологиям определить его название.
Сохраните браузерное поведение
Используйте form для отправки и button с type="submit". Для обычного действия внутри формы задавайте type="button". Если обрабатываете отправку сами, вызывайте preventDefault в onSubmit и показывайте результат рядом с формой.
Практика
Добавьте сообщение о неверном адресе, свяжите его с полем через aria-describedby и проверьте форму только клавиатурой. Не убирайте видимый индикатор фокуса.