- React + TypeScript: Handling onClick event
- Example 1: Button onClick
- App Preview
- The Code
- Example 2: onClick event fired on an arbitrary element
- A Common Pitfall
- App Preview
- The Code
- Conclusion
- TypeScript and React: Events
- Basic Event Handling #
- Restrictive Event Handling #
- Where’s InputEvent? #
- Typescript event types for React
React + TypeScript: Handling onClick event
The onClick event occurs when an element is clicked. This element can be a button, a div element, an image, etc.
This article walks you through a couple of different examples of handling the onClick event in a React app that is written in TypeScript. We’ll see the modern features of React like hooks and functional components.
Example 1: Button onClick
App Preview
This tiny app contains 4 different buttons but we will only use a single function to handle the onClick events that fired when one of them clicked. The name of the clicked button will be displayed on the screen. We also call the preventDefault() method to prevent it from submitting the form.
The Code
1. Create a brand new React project:
npx create-react-app kindacode_example --template typescript
2. Remove the default code in src/App.tsx and add the following:
// App.tsx // Kindacode.com import React, < useState >from "react"; import "./App.css"; const App = (): JSX.Element => < const [clickedButton, setClickedButton] = useState(''); const buttonHandler = (event: React.MouseEvent) => < event.preventDefault(); const button: HTMLButtonElement = event.currentTarget; setClickedButton(button.name); >; return ( Kindacode.com
"` : "No button clicked yet">
); >; export default App;
3. Replace unwanted CSS in src/App.css with the code below:
/* App.css Kindacode.com */ .container < margin: 30px auto; width: 500px; display: flex; flex-direction: column; justify-content: center; align-items: center; >.button < margin: 10px 5px; padding: 15px 30px; background: purple; color: white; cursor: pointer; border-radius: 30px; border: none; >.button:hover < background: orangered; >h1
4. Run the project and navigate to http://localhost:3000 on your browser.
Example 2: onClick event fired on an arbitrary element
A Common Pitfall
When an element nests inside another element, the onClick event may be triggered on both the child and the parent when the child is clicked. In general, that is not what we want.
To prevent the event of the parent from being fired in this case, we need to call:
App Preview
This sample React app contains 3 elements:
- div: The parent element that contains 2 other children.
- img: This image is a child of the parent div.
- h1: This heading is a child of the parent div.
When an element is clicked, information about its size and tag name will be displayed in the console logs.
The Code
// App.tsx // Kindacode.com import React from "react"; import "./App.css"; const App = () => < // This function will be triggered when the "container" is clicked const divClickedHandler = (event: React.MouseEvent) => < const div = event.currentTarget; console.log( "Element name: ", div.tagName, "Width: ", div.clientWidth, "Height: ", div.clientHeight ); >; // This function will be triggered when the headline is clicked const headingClickedHandler = ( event: React.MouseEvent ) => < event.stopPropagation(); const heading = event.currentTarget; console.log( "Element name: ", heading.tagName, "Width: ", heading.clientWidth, "Height: ", heading.clientHeight ); >; // This function will be triggered when the image is clicked const imgClickedHandler = (event: React.MouseEvent) => < event.stopPropagation(); const img = event.currentTarget; console.log( "Element name: ", img.tagName, "Width: ", img.clientWidth, "Height: ", img.clientHeight ); >; return ( > >Kindacode.com
/>
); >; export default App;
/* App.css Kindacode.com */ .container
Conclusion
We’ve examined 2 end-to-end examples of handling the onClick event in React and TypeScript. If you’d like to learn more new and interesting things about modern React and front-end development, take a look at the following articles:
You can also check our React category page and React Native category page for the latest tutorials and examples.
TypeScript and React: Events
Web apps are really boring if you don’t interact with them. Events are key, and TypeScript’s React typings have great support for them.
Basic Event Handling #
React uses its own event system. That’s why you can’t use typical MouseEvent s or similar on your elements. You need to use the specific React version, otherwise you get a compile error.
Luckily, React typings give you the proper equivalent of each event you might be familiar with from standard DOM. They even have the same name, which can be tricky at times. You either need to be specific with e.g. React.MouseEvent or import the MouseEvent typing right from the React module:
import React, Component, MouseEvent > from 'react';
export class Button extends Component
handleClick(event: MouseEvent)
event.preventDefault();
alert(event.currentTarget.tagName); // alerts BUTTON
>
render()
return button onClick=this.handleClick>>
this.props.children>
/button>
>
>
Restrictive Event Handling #
If you want to restrict your event handlers to specific elements, you can use a generic to be more specific:
import React, Component, MouseEvent > from 'react';
export class Button extends Component
/*
Here we restrict all handleClicks to be exclusively on
HTMLButton Elements
*/
handleClick(event: MouseEventHTMLButtonElement>)
event.preventDefault();
alert(event.currentTarget.tagName); // alerts BUTTON
>
/*
Generics support union types. This event handler works on
HTMLButtonElement and HTMLAnchorElement (links).
*/
handleAnotherClick(event: MouseEventHTMLButtonElement | HTMLAnchorElement>)
event.preventDefault();
alert('Yeah!');
>
render()
return button onClick=this.handleClick>>
this.props.children>
/button>
>
>
All HTML element type definitions are in the default DOM typings of TypeScript. Don’t forget to add the library dom (see getting started).
Where’s InputEvent? #
If you come from Flow you will notice that InputEvent ( SyntheticInputEvent respectively) is not supported by TypeScript typings. This is mainly because InputEvent is still an experimental interface and not fully supported by all browsers. If you use the onInput property from all input elements, you will see that the interface for onInput uses any for the event interface. This will change in the future.
To be a bit more specific in your code you can import SyntheticEvent from the React typings.
import React, Component, SyntheticEvent > from 'react';
export class Input extends Component
handleInput(event: SyntheticEvent)
event.preventDefault();
// .
>
render()
return >
input type="text" onInput=this.handleInput>/>
/>
>
>
Now you get at least some type safety.
Typescript event types for React
When you migrate your React applications from Javascript to Typescript you want everything to be typed right! and If you start having the type any it means that you are in the wrong direction 😞 Ok cool, you have to create your own types, interfaces. but what about React types, for instance React Events types.
For instance you have a submit event
const handleSubmit = (event) => < event.preventDefault() const data = new FormData(event.currentTarget) console.log(< email: data.get('email'), password: data.get('password'), >) >
Typescript is complaining and you need to provide a type for your event You need to know what type is your event here, but how? 🤔
All what you have to do is to write an inline event handler and hover over the event parameter to know that it’s of type React.FormEvent 👍 Great! Here is your new code and Typescript is happy
const handleSubmit = (event: React.FormEvent) => < .
Till now everything is good but can't you see that it's a long ugly type 😫 You can make it shorter and nicer. Let us create a new types file types.ts where we can create new types or in our case only renaming existing ugly ones. Examples bellow
type FormEvent = React.FormEvent type MouseEvent = React.MouseEvent type ChangeEvent = React.ChangeEvent . export < FormEvent, MouseEvent, ChangeEvent >;
Now our React.FormEvent
import < FormEvent >from './types' const handleSubmit = (event: FormEvent) => < .