Skip to main content

Forms and Events

If performance is not an issue (and it usually isn't!), inlining handlers is easiest as you can just use type inference and contextual typing:

const el = (
<button
onClick={(event) => {
/* event will be correctly typed automatically! */
}}
/>
);

But if you need to define your event handler separately, IDE tooling really comes in handy here, as the @type definitions come with a wealth of typing. Type what you are looking for and usually the autocomplete will help you out. Here is what it looks like for an onChange for a form event:

type State = {
text: string;
};
class App extends React.Component<Props, State> {
state = {
text: "",
};

// typing on RIGHT hand side of =
onChange = (e: React.FormEvent<HTMLInputElement>): void => {
this.setState({ text: e.currentTarget.value });
};
render() {
return (
<div>
<input type="text" value={this.state.text} onChange={this.onChange} />
</div>
);
}
}

View in the TypeScript Playground

Instead of typing the arguments and return values with React.FormEvent<> and void, you may alternatively apply types to the event handler itself (contributed by @TomasHubelbauer):

  // typing on LEFT hand side of =
onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
this.setState({text: e.currentTarget.value})
}
Why two ways to do the same thing?

The first method uses an inferred method signature (e: React.FormEvent<HTMLInputElement>): void and the second method enforces a type of the delegate provided by @types/react. So React.ChangeEventHandler<> is simply a "blessed" typing by @types/react, whereas you can think of the inferred method as more... artisanally hand-rolled. Either way it's a good pattern to know. See our Github PR for more.

Typing onSubmit, with Uncontrolled components in a Form

If you don't quite care about the type of the event, you can just use React.SyntheticEvent. If your target form has custom named inputs that you'd like to access, you can use a type assertion:

<form
ref={formRef}
onSubmit={(e: React.SyntheticEvent) => {
e.preventDefault();
const target = e.target as typeof e.target & {
email: { value: string };
password: { value: string };
};
const email = target.email.value; // typechecks!
const password = target.password.value; // typechecks!
// etc...
}}
>
<div>
<label>
Email:
<input type="email" name="email" />
</label>
</div>
<div>
<label>
Password:
<input type="password" name="password" />
</label>
</div>
<div>
<input type="submit" value="Log in" />
</div>
</form>

View in the TypeScript Playground

Of course, if you're making any sort of significant form, you should use Formik or React Hook Form, which are written in TypeScript.

List of event types

Event TypeDescription
AnimationEventCSS Animations.
ChangeEventChanging the value of <input>, <select> and <textarea> element.
ClipboardEventUsing copy, paste and cut events.
CompositionEventEvents that occur due to the user indirectly entering text (e.g. depending on Browser and PC setup, a popup window may appear with additional characters if you e.g. want to type Japanese on a US Keyboard)
DragEventDrag and drop interaction with a pointer device (e.g. mouse).
FocusEventEvent that occurs when elements gets or loses focus.
FormEventEvent that occurs whenever a form or form element gets/loses focus, a form element value is changed or the form is submitted.
InvalidEventFired when validity restrictions of an input fails (e.g <input type="number" max="10"> and someone would insert number 20).
KeyboardEventUser interaction with the keyboard. Each event describes a single key interaction.
MouseEventEvents that occur due to the user interacting with a pointing device (e.g. mouse)
PointerEventEvents that occur due to user interaction with a variety pointing of devices such as mouse, pen/stylus, a touchscreen and which also supports multi-touch. Unless you develop for older browsers (IE10 or Safari 12), pointer events are recommended. Extends UIEvent.
TouchEventEvents that occur due to the user interacting with a touch device. Extends UIEvent.
TransitionEventCSS Transition. Not fully browser supported. Extends UIEvent
UIEventBase Event for Mouse, Touch and Pointer events.
WheelEventScrolling on a mouse wheel or similar input device. (Note: wheel event should not be confused with the scroll event)
SyntheticEventThe base event for all above events. Should be used when unsure about event type
What about InputEvent?

You've probably noticed that there is no InputEvent. This is because it is not supported by Typescript as the event itself has no fully browser support and may behave differently in different browsers. You can use KeyboardEvent instead.

Sources: