//
Search across all documentation pages
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Type React event handlers correctly for clicks, form submissions, input changes, keyboard events, and custom event callbacks. Use React's synthetic event types for full type safety.
// Click event
function handleClick(event: React.MouseEvent<HTMLButtonElement>) {
console.log("Button clicked at", event.clientX, event.clientY);
}
// Form submit event
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const email = formData.get("email") as string;
console.log("Submitted:", email);
}
// Input change event
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
console.log("Value:", event.target.value);
}
// Keyboard event
function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
if (event.key === "Enter") {
console.log("Enter pressed");
}
}// Full form component
function LoginForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log({ email, password });
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Escape") setEmail("");
}}
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Log In</button>
</form>
);
}SyntheticEvent objects. TypeScript provides generic event types like React.MouseEvent<T> where T is the HTML element type.event.target is typed as EventTarget, which is broad. Use event.currentTarget for the element the handler is attached to -- it is typed as the generic parameter (HTMLButtonElement, HTMLInputElement, etc.).onChange={(e) => ...}), TypeScript infers the event type automatically from the JSX attribute.Select and textarea:
function handleSelectChange(event: React.ChangeEvent<HTMLSelectElement>) {
console.log("Selected:", event.target.value);
}
function handleTextareaChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
console.log("Text:", event.target.value);
}Drag events:
function handleDragStart(event: React.DragEvent<HTMLDivElement>) {
event.dataTransfer.setData("text/plain", "dragged");
}Focus events:
function handleFocus(event: React.FocusEvent<HTMLInputElement>) {
event.currentTarget.select();
}Custom event callback props:
type SearchBarProps = {
onSearch: (query: string) => void;
onClear?: () => void;
};
function SearchBar({ onSearch, onClear }: SearchBarProps) {
const [query, setQuery] = useState("");
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
onSearch(query);
};
return (
<form onSubmit={handleSubmit}>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<button type="submit">Search</button>
{onClear && <button type="button" onClick={onClear}>Clear</button>}
</form>
);
}React.MouseEvent, React.ChangeEvent, React.FormEvent, React.KeyboardEvent, React.FocusEvent, React.DragEvent, React.TouchEvent, React.WheelEvent.currentTarget. For example, React.MouseEvent<HTMLAnchorElement> gives currentTarget the type HTMLAnchorElement.React.SyntheticEvent is the base type for all React events. Use it when you do not care about the specific event type.event.target vs event.currentTarget: target is the element that triggered the event (could be a child), while currentTarget is the element the handler is attached to. TypeScript types currentTarget more precisely.event.target.value on a form submit event will error because EventTarget does not have a value property. Cast it or use currentTarget.event.preventDefault() on form submit causes a full page reload.| Approach | Pros | Cons |
|---|---|---|
| Inline arrow functions | TypeScript infers event type automatically | Creates new function on each render |
| Named handler functions | Reusable, testable, no re-creation | Must manually annotate event type |
React.EventHandler<E> type | Concise handler type alias | Less common, slightly harder to read |
Callback prop (e.g., onSearch: (q: string) => void) | Decouples parent from DOM events | Parent does not have access to raw event |
useCallback wrapped handler | Stable reference for memoized children | Additional boilerplate |
event.target is the element that triggered the event (could be a child element).event.currentTarget is the element the handler is attached to.currentTarget more precisely based on the generic parameter.onChange={(e) => ...} get their type from the JSX attribute context.function handleChange(e: React.ChangeEvent<HTMLInputElement>).React.MouseEvent<T> -- clicks, mouse movement.React.ChangeEvent<T> -- input, select, textarea changes.React.FormEvent<T> -- form submissions.React.KeyboardEvent<T> -- key presses.React.FocusEvent<T> -- focus and blur.event.target is typed as EventTarget, which does not have a value property.event.currentTarget (typed as the form element) or cast event.target.new FormData(event.currentTarget).type SearchBarProps = {
onSearch: (query: string) => void;
onClear?: () => void;
};onSearch(query)) instead of the raw DOM event.event.currentTarget.React.MouseEvent<HTMLButtonElement> means currentTarget is typed as HTMLButtonElement.event.preventDefault() at the top of form submit handlers.clientX, key).function handleSelectChange(event: React.ChangeEvent<HTMLSelectElement>) {
console.log("Selected:", event.target.value);
}React.ChangeEvent<HTMLSelectElement> -- not HTMLInputElement.value property is the string value of the selected option.event.persist().persist().Reviewed by Chris St. John·Last updated Jul 7, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥