cf.completefrontend
Open lab My progress
THE REACT FIELD GUIDE

Responding to events

Handle clicks, typing, and form submits in React: write event handlers, pass them as props, and control bubbling with stopPropagation and preventDefault.

By the end, you can
  • 01
    Write and pass event handlersGive an element a function to run on a click or a key, and pass handlers down to your own components with on… props.
  • 02
    Follow an event through the treeSay which handlers run for a click, in what order, and stop the click going up with stopPropagation.
  • 03
    Stop the browser's own actionKeep a form from loading a new page with preventDefault, and tell it apart from stopPropagation.

A button that answers a click

So far, your components have described what the screen shows. Now they start to answer the person using it. When someone clicks, types, or sends a form, the browser fires an event. In plain JavaScript you'd find the element and call addEventListener. In React you give the element a function, as a prop, in your JSX:

An Add to cart button with a click handlerPop out in the code editor (opens in a new tab)JSX
export default function AddToCart() {  function handleClick() {    console.log("Added Masala chai to the cart");  }   return <button onClick={handleClick}>Add to cart</button>;}
ResultLoading…

Lines 2 to 4 define handleClick, a function inside the component. Line 6 hands it to the button as onClick. React keeps it, and calls it each time the button is clicked. A function like this, which runs when an event happens, is an event handler. Click Add to cart in the result: the console under it says Added Masala chai to the cart, once per click.

The prop's name says which event: onClick for clicks, onChange for typing, onSubmit for forms. They're written in camelCase, like the other JSX attributes in Writing markup with JSX. The examples print to the console instead of changing the screen, because changing the screen needs state, the next lesson's topic. A handler is where that change will happen.

Real-life analogyA doorbell

When you install a doorbell, you connect it to the button and leave. It rings later, each time someone presses, not while you're wiring it.

In real life: Wiring a bell to the button by the door
In React: onClick={handleClick} on the <button>
In real life: The bell itself, waiting on the wall
In React: The handleClick function, kept by React
In real life: A visitor pressing the button
In React: A click, which the browser reports as an event
In real life: The bell rings, each press, never while you install it
In React: React calls handleClick on each click, never while rendering
The main idea

An event handler is a function you give React to run when something happens. Pass it to a built-in element with a prop like onClick. React calls it with an event object. Then the event goes on to the handlers of the elements around it, unless you stop it.

Pass the function, don't call it

The braces in onClick={handleClick} hold a JavaScript value, and that value must be a function. Add two brackets, and it isn't one any more. Here is the overview's button with that one change, a bug on purpose:

handleClick() runs while rendering (a bug on purpose)Pop out in the code editor (opens in a new tab)JSX
export default function AddToCart() {  function handleClick() {    console.log("Added Masala chai to the cart");  }   return <button onClick={handleClick()}>Add to cart</button>;}
ResultLoading…

Line 6 now says handleClick(). JavaScript inside braces runs right away, so handleClick runs while React renders the button, and onClick gets what it returns: undefined. Look at the console: the message is already there before any click, with a 2 beside it because it ran twice. (Twice because the preview renders in StrictMode, which calls each component two times in development, as Keeping components pure showed.) Click the button: nothing more is printed. Press Edit & run and delete the (): the console starts empty, and each click adds a line.

Two columns. Left, onClick={handleClick}: React keeps the function handleClick, and on a click, handleClick(e) runs. Right, onClick={handleClick()}: handleClick runs while rendering and gives undefined, which React keeps, so a click runs nothing.PassedonClick={handleClick}handleClickReact keeps the functiona clickhandleClick(e) runsCalledonClick={handleClick()}undefinedit ran while renderinga clicknothing runs
Left: onClick={handleClick} hands React the function, and React calls it on each click. Right: the brackets in handleClick() run it while React renders, and onClick gets what it returns, undefined.

When the handler needs something passed in, wrap the call in an arrow function instead. The arrow function is what onClick gets, and it makes the call later, on the click:

Handlers that read props and pass argumentsPop out in the code editor (opens in a new tab)JSX
function addToCart(tea, cups) {  console.log(`Added ${cups} x ${tea}`);} function TeaButton({ tea }) {  function handleClick() {    addToCart(tea, 1);  }   return (    <p>      <button onClick={handleClick}>Add {tea}</button>      <button onClick={() => addToCart(tea, 2)}>Add 2</button>    </p>  );} export default function Menu() {  return (    <>      <TeaButton tea="Masala chai" />      <TeaButton tea="Matcha" />    </>  );}
ResultLoading…
  1. Lines 1 to 3 are an ordinary function, addToCart, that takes a tea and a number of cups.
  2. Lines 6 to 8 define handleClick inside TeaButton. Because it's inside, it can read the tea prop: each TeaButton gets its own handleClick, with its own tea. That's a closure.
  3. Line 12 passes handleClick by name. Line 13 writes the handler inline, as an arrow function: () => addToCart(tea, 2). Both are functions, so both wait for a click.
  4. Lines 21 and 22 use the component twice, so there are four buttons.

Click Add Matcha: the console says Added 1 x Matcha. Click the Add 2 next to it: Added 2 x Matcha. Writing onClick={addToCart(tea, 2)} without the arrow would run while rendering, like the bug above. A named handler and an inline arrow work the same; inline is handy for one short call.

Passing handlers down as props

A handler is a function, and a function can be a prop, as Passing props to a component showed. That lets one component decide what happens, and another decide how it looks. Here, Button draws every button in a profile toolbar the same way, and each parent gives it a different job:

One Button, two jobs, chosen by the parentsPop out in the code editor (opens in a new tab)JSX
function Button({ onClick, children }) {  return (    <button className="button" onClick={onClick}>      {children}    </button>  );} function SaveButton() {  function handleSaveClick() {    console.log("Saved your profile");  }   return <Button onClick={handleSaveClick}>Save</Button>;} function ResetButton() {  return <Button onClick={() => console.log("Put back your old details")}>Reset</Button>;} export default function ProfileToolbar() {  return (    <div className="toolbar">      <SaveButton />      <ResetButton />    </div>  );}
ResultLoading…

Button (lines 1 to 7) takes an onClick prop and passes it to the real <button> on line 3. SaveButton passes its own handleSaveClick on line 14, and ResetButton passes an inline arrow function on line 18. Click Save, then Reset: each prints its own line. Design systems work this way: their buttons bring the look, and your code brings the behavior.

Naming: on for props, handle for functions

Built-in elements like <button> only take React's event names, spelled exactly: onClick, onChange. Your own components can take any prop names. By habit, a prop that takes a handler starts with on and a capital letter, and the function you pass starts with handle. Name props after what happens in your app, not after the mouse:

Props named for what happens in the shopPop out in the code editor (opens in a new tab)JSX
function ProductCard({ name, price, onShowDetails, onAddToCart }) {  return (    <article className="card">      <h3>{name}</h3>      <p>${price}</p>      <button onClick={onShowDetails}>Details</button>      <button onClick={() => onAddToCart(name)}>Add to cart</button>    </article>  );} export default function Shop() {  function handleAddToCart(name) {    console.log(`${name} added to the cart`);  }   return (    <div className="shelf">      <ProductCard        name="Matcha"        price={6}        onShowDetails={() => console.log("Showing Matcha's details")}        onAddToCart={handleAddToCart}      />      <ProductCard        name="Sencha"        price={4}        onShowDetails={() => console.log("Showing Sencha's details")}        onAddToCart={handleAddToCart}      />    </div>  );}
ResultLoading…

ProductCard takes onShowDetails and onAddToCart on line 1. Line 6 passes onShowDetails straight to the Details button. Line 7 wraps onAddToCart in an arrow function, so it can pass the card's name. Shop defines handleAddToCart once, on lines 13 to 15, and gives it to both cards on lines 23 and 29. Click Add to cart on Sencha: Sencha added to the cart. Shop doesn't know a button was involved; later, the same prop could be called from a keyboard shortcut.

Three function cards from top to bottom: Shop, ProductCard, and the button element. Arrows down are labelled onAddToCart={handleAddToCart} and onClick={() => onAddToCart(name)}. A curved arrow on the left leads from the button back up to Shop, labelled: a click calls Shop's handleAddToCart.ShoponAddToCart={handleAddToCart}ProductCardonClick={() => onAddToCart(name)}<button>a click callsShop's handleAddToCart
Shop passes its function down as onAddToCart, and ProductCard passes a function to the <button>. A click runs that function, which calls Shop's handleAddToCart: the click comes back up to where the function was written.

How to read the table: each row is a name you might write, what it is, and whether React runs it on its own.

Names for events
When you writeWhat it isDoes React run it on a click?
onClick on <button>A browser event that React knows.Yes. Built-in elements only take React's event names, spelled exactly.
onAddToCart on <ProductCard>A prop of your own component.Only if ProductCard passes it to an element, or calls it.
onClick on <ProductCard>Also just a prop, with a familiar name.Only if ProductCard uses it. React doesn't attach it for you.
handleAddToCartA function that handles something, by the usual naming.It's the function you pass, not a prop name.

One more habit from React's documentation: put click handlers on elements made for clicking, like <button>. A <div onClick> works with a mouse, but it can't be reached with the Tab key or pressed with Enter, so people who use a keyboard can't use it.

The event object React passes in

React calls your handler with one argument: an event object describing what happened. By habit it's called e. It has the properties you know from the browser's events, like type and target:

A search box that reads its eventsPop out in the code editor (opens in a new tab)JSX
export default function SearchBox() {  function handleClick(e) {    console.log(e.type, "on", e.target.tagName, "handled by", e.currentTarget.tagName);  }   function handleChange(e) {    console.log("Search for:", e.target.value);  }   return (    <div onClick={handleClick}>      <input placeholder="Search teas" onChange={handleChange} />      <button>Search</button>    </div>  );}
ResultLoading…

Line 11 puts handleClick on the <div>, not on the button. Click Search: the console says click on BUTTON handled by DIV. e.target is the element that was clicked, and e.currentTarget is the element whose handler is running. They differ because the click travelled from the button to the <div>, which the next section explains. Now type chai in the box: line 7 prints Search for: c, then ch, then cha, then chai. In React, onChange runs on every change to an input's value, on each key, unlike the browser's own change event, which waits until you leave the box. (Clicking into the box prints a click line too: the box is inside the <div>.)

e isn't the browser's event itself. React gives you its own event object, sometimes called a synthetic event. It follows the same standard as the browser's, with the same properties and methods, and fixes a few differences between browsers. The browser's original is inside it, as e.nativeEvent:

React's event and the browser's event inside itPop out in the code editor (opens in a new tab)JSX
export default function Inspect() {  function handleClick(e) {    console.log("React's event:", e.type);    console.log("The browser's event inside it:", e.nativeEvent.type);    console.log("The same object?", e === e.nativeEvent);  }   return <button onClick={handleClick}>Inspect this click</button>;}
ResultLoading…

Click the button. Lines 3 and 4 both say click, and line 5 says The same object? false: two objects, one inside the other. You'll rarely need nativeEvent. One more thing React does for you: it doesn't add a listener to each element. When your app starts, it adds its own listeners, for every kind of event, to the root element your app is rendered into. When an event reaches the root, React works out which of your handlers to call. That's why the next section can talk about a click travelling through your components. A later lesson, React's event system, opens it up.

How to read the table: each row is an event prop you'll use often, what it reports, and whether it goes up to the elements around it.

Events you'll use most
PropWhat runs itGoes up to the elements around it?
onClickA click, or Enter and Space on a focused button.Yes.
onChange on an inputEvery change to its value, on each key you type.Yes.
onSubmit on a formThe form being sent, by a button or Enter.Yes.
onKeyDownA key being pressed, with e.key naming it.Yes.
onFocus and onBlurAn element getting or losing focus.Yes, in React.
onMouseEnter and onMouseLeaveThe pointer moving onto or off an element.No. Each runs only on its own element.
onScrollThe element being scrolled.No. It runs only on the element you attach it to.

A click bubbles up the tree

A click on a button is also a click on everything around it. So after the button's onClick, React runs the onClick of each element around it, from the inside out. That's called bubbling, or propagation, the same idea as in the browser's bubbling and capturing. On a product card it causes a bug:

A clickable card with a button inside (a bug on purpose)Pop out in the code editor (opens in a new tab)JSX
export default function ProductCard() {  return (    <article className="card" onClick={() => console.log("card: open Matcha's page")}>      <h3>Matcha</h3>      <button onClick={() => console.log("button: add Matcha to the cart")}>        Add to cart      </button>    </article>  );}
ResultLoading…

Line 3 makes the whole card open the product's page. Line 5 gives the button its own job, adding to the cart. Click Add to cart. The console shows two lines: button: add Matcha to the cart, then card: open Matcha's page. The click bubbled from the button up to the card. Click the word Matcha instead: only the card's line, because nothing inside the card was clicked.

To stop it, call e.stopPropagation() in the button's handler. It tells React not to run the handlers above:

The button stops the click from reaching the cardPop out in the code editor (opens in a new tab)JSX
export default function ProductCard() {  return (    <article className="card" onClick={() => console.log("card: open Matcha's page")}>      <h3>Matcha</h3>      <button        onClick={(e) => {          e.stopPropagation();          console.log("button: add Matcha to the cart");        }}      >        Add to cart      </button>    </article>  );}
ResultLoading…

Line 6 now takes the event, e, and line 7 stops it before line 8 prints. Click Add to cart: one line, from the button. The card's handler never runs. The heading still opens the card.

Bubbling is the second half of the trip. Before it, the event travels down from the outside to what you clicked, and React runs any capture handlers on the way: the same name with Capture at the end, like onClickCapture.

Three cards stacked from top to bottom: section, article, and button, which was clicked. An arrow on the left runs down, labelled capture, onClickCapture, outside in. An arrow on the right runs up, labelled bubble, onClick, inside out.<section><article><button>you click here1. captureonClickCaptureoutside in2. bubbleonClickinside out
For a click on the button, React first runs every onClickCapture on the way down, from the outside in. Then it runs onClick on the button and on each element around it, from the inside out: the click bubbles up.

Try it, with real React handlers on this page:

Playground: in what order do the handlers run?
ShopPage, with the handlers you pickedJSX
export default function ShopPage() {
  return (
    <section
      onClickCapture={() => console.log("section onClickCapture")}
      onClick={() => console.log("section onClick")}
    >
      Shop page
      <article
        onClickCapture={() => console.log("article onClickCapture")}
        onClick={() => console.log("article onClick")}
      >
        Matcha card
        <button
          onClickCapture={() => console.log("button onClickCapture")}
          onClick={() => console.log("button onClick")}
        >
          Add to cart
        </button>
      </article>
    </section>
  );
}
On the pageclick inside
Shop page
Matcha card
    Try it yourself
    Capture handlers on, stopPropagation off

    Click Add to cart in the result, then the card around it, then the page around the card. Switch the handlers on and off between clicks.

    React renders this section, article, and button on the page with the handlers in the code. Each handler adds its name to the list when React calls it, so the list is the order they really ran. Reset turns capture on and stopPropagation off.

    With capture on, a click on Add to cart runs six handlers: section onClickCapture, article onClickCapture, button onClickCapture on the way down, then button onClick, article onClick, section onClick on the way up. Click the card itself, and only four run: the button isn't on the path. Switch on stopPropagation() in the button and click the button again: four, because the capture handlers had already run when the button stopped the click.

    That last point is what capture handlers are for. A stopped click is still seen by every capture handler above it, so they suit code that must see every click, like analytics:

    An analytics handler that sees every clickPop out in the code editor (opens in a new tab)JSX
    export default function Shop() {  function handleAnyClick(e) {    console.log("analytics:", e.target.tagName, "clicked");  }   return (    <main onClickCapture={handleAnyClick}>      <article className="card" onClick={() => console.log("card: open Matcha's page")}>        <h3>Matcha</h3>        <button          onClick={(e) => {            e.stopPropagation();            console.log("button: add Matcha to the cart");          }}        >          Add to cart        </button>      </article>    </main>  );}
    ResultLoading…

    Line 7 puts handleAnyClick on <main> as onClickCapture. Click Add to cart: the console says analytics: BUTTON clicked first, then the button's line. The button's stopPropagation on line 12 still keeps the card from opening, but it can't take back a capture handler that ran before it. You'll rarely write capture handlers in app code; routers and analytics tools use them.

    Bubbling is automatic, which makes it easy to forget. If it gets hard to tell which handlers run, there's a plainer way: the child handles its own click and then calls the prop from its parent, as the inbox below does. Every step is then in the code you read.

    preventDefault: stop the browser's own action

    Some events come with something the browser does by itself, its default action. A link loads its address. A form's submit event sends the form and loads a new page. In a React app, that new page throws away your app. e.preventDefault() cancels the default action:

    A newsletter form that stays on the pagePop out in the code editor (opens in a new tab)JSX
    export default function NewsletterForm() {  function handleSubmit(e) {    e.preventDefault();    const data = new FormData(e.currentTarget);    console.log("Subscribing", data.get("email"));  }   return (    <form onSubmit={handleSubmit}>      <input name="email" aria-label="Email" defaultValue="asha@example.com" />      <button>Subscribe</button>    </form>  );}
    ResultLoading…

    Line 9 handles onSubmit on the form, not onClick on the button, so pressing Enter in the box submits too. Line 3 cancels the browser's own submit. Line 4 reads every named field with FormData, and line 5 prints the email. Press Subscribe: the console says Subscribing asha@example.com. Now press Edit & run, delete line 3, and press Subscribe again. Your line still prints, followed by a note from the preview: it caught the submit itself. On a real page nothing would catch it, and the browser would send the form and load a new page, throwing your app away.

    The same works for a link that should do something else instead of loading its address:

    A link that opens a drawer insteadPop out in the code editor (opens in a new tab)JSX
    export default function MiniCart() {  function handleClick(e) {    e.preventDefault();    console.log("Opening the cart drawer instead of the cart page");  }   return (    <a href="/cart" onClick={handleClick}>      View cart    </a>  );}
    ResultLoading…

    Line 3 keeps the browser from going to /cart, so line 4 can open a drawer instead. Click View cart: the page stays, and the console prints the line. Delete line 3 with Edit & run and click again: now the link tries to load /cart, and the preview says it has no such page.

    Left, e.stopPropagation() in the button's onClick: the button's handler runs, and the card's onClick above it is crossed out. Right, e.preventDefault() in a form's onSubmit: the handler runs, and the browser loading a new page is crossed out.e.stopPropagation()card onClickdoesn't runbutton onClick runsstops the event goingup your componentse.preventDefault()browser loads a pagedoesn't happenonSubmit runsstops the browser'sown action
    e.stopPropagation() keeps the event from reaching the handlers above, in your components. e.preventDefault() keeps the browser from doing its own thing, like loading a new page for a form. One doesn't do the other's job.

    Don't mix up the two. e.stopPropagation() stops the handlers above, in your components, from running. e.preventDefault() stops the browser's own action. A form that reloads needs preventDefault; a card that opens when you meant the button needs stopPropagation.

    React 19 adds another way for forms: pass a function as the form's action, like <form action={subscribe}>, and React handles the submit for you, without a reload. The Form actions lesson teaches them. onSubmit with preventDefault keeps working, and you'll see it in most code written before React 19.

    An inbox with three kinds of click

    Here everything comes together in one small app: rows that open, a button inside each row that shouldn't, and a form that mustn't reload.

    An inbox: open, archive, and replyPop out in the code editor (opens in a new tab)JSX
    const messages = [  { id: 1, from: "Asha", subject: "Your order has shipped" },  { id: 2, from: "Ravi", subject: "Matcha is back in stock" },]; function MessageRow({ message, onOpen, onArchive }) {  function handleArchiveClick(e) {    e.stopPropagation();    onArchive(message.id);  }   return (    <li className="row" onClick={() => onOpen(message.id)}>      <strong>{message.from}</strong>      <span>{message.subject}</span>      <button onClick={handleArchiveClick}>Archive</button>    </li>  );} function ReplyForm({ onSend }) {  function handleSubmit(e) {    e.preventDefault();    onSend(new FormData(e.currentTarget).get("reply"));  }   return (    <form onSubmit={handleSubmit}>      <input name="reply" aria-label="Reply" defaultValue="Thanks!" />      <button>Send</button>    </form>  );} export default function Inbox() {  return (    <>      <ul className="inbox">        {messages.map((message) => (          <MessageRow            key={message.id}            message={message}            onOpen={(id) => console.log("Open message", id)}            onArchive={(id) => console.log("Archive message", id)}          />        ))}      </ul>      <ReplyForm onSend={(text) => console.log("Send reply:", text)} />    </>  );}
    ResultLoading…
    • Rows open on a click: line 13 calls onOpen with the message's id. Click Asha's subject: Open message 1.
    • Archive doesn't open the row: handleArchiveClick on lines 7 to 10 stops the click, then calls the parent's onArchive itself. Click Archive on Ravi's row: only Archive message 2.
    • The reply form doesn't reload: line 23 cancels the submit, and line 24 hands the text to onSend. Press Send: Send reply: Thanks!.
    • Inbox decides what each one does: lines 43, 44, and 48 pass the handlers down. The rows and the form only report what happened.

    A real inbox would also let keyboard users open a row, for example by making the subject a button or a link. The row's onClick here keeps the example small.

    Sort each problem by the call that fixes it:

    stopPropagation or preventDefault?
    • A newsletter form reloads the page when you press Subscribe
    • Clicking Delete on a note also opens the note
    • A View cart link should open a drawer, not go to /cart
    • A click inside a modal also closes it, through the backdrop's onClick
    • Ticking a row's checkbox also selects the whole row
    • Right-click should show your own menu, not the browser's
    • Space in your game scrolls the page down
    • Add to cart on a product card also opens the product page
    Try it yourself
    0 of 8 correct

    Drag each problem, or pick it and choose a group. Ask: is a handler above running when it shouldn't, or is the browser doing something by itself?

    Choose a category for every card. You can change an answer at any time; Reset clears them all.

    Common mix-ups

    • "onClick={handleClick()} runs handleClick on a click." No. The brackets call it while React renders. Pass handleClick, or an arrow function.
    • "Any component understands onClick." No. Only built-in elements like <button> do. On your own component, onClick is just a prop until the component passes it to an element.
    • "stopPropagation stops a form from reloading." No. That's preventDefault. stopPropagation only stops the handlers above.
    • "Only the clicked element's onClick runs." No. The click bubbles: every onClick around it runs too, unless one stops it.
    • "Returning false from a handler cancels the default." No. React ignores what a handler returns. Call e.preventDefault().
    • "e is the browser's event." Not quite. It's React's event object, with the browser's inside, in e.nativeEvent.

    Practice exercises

    Each exercise shows its result under the code, or when you press Edit & run, and its console under the result. For the first one, answer before you run anything.

    Exercise 1 · Warm-upPredict the console

    You click Track once. What does the console show, in order?

    export default function OrderRow() {
      return (
        <div onClick={() => console.log("row")}>
          Order #12
          <button onClick={() => console.log("button")}>Track</button>
        </div>
      );
    }

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 2 · Warm-upA Like button that likes too early

      The console says You liked Matcha before anyone clicks, and clicking does nothing. Fix it. Then: before you click, how many lines does the console show?

      export default function LikeButton() {  function handleLike() {    console.log("You liked Matcha");  }   return <button onClick={handleLike()}>Like</button>;}
      ResultLoading…

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 3 · PracticeWire up a quantity stepper

        The + and - buttons do nothing. Connect them to the handlers CartLine passes in. What does the console show after + twice?

        function QuantityStepper({ quantity, onIncrease, onDecrease }) {  return (    <p>      <button>-</button> {quantity} <button>+</button>    </p>  );} export default function CartLine() {  return (    <QuantityStepper      quantity={2}      onIncrease={() => console.log("Quantity + 1")}      onDecrease={() => console.log("Quantity - 1")}    />  );}
        ResultLoading…

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 4 · PracticeDelete without opening

          Clicking Delete deletes the note and also opens it. Make Delete only delete. What does one click print now?

          function NoteRow({ note, onOpen, onDelete }) {  return (    <li onClick={() => onOpen(note.id)}>      {note.title} <button onClick={() => onDelete(note.id)}>Delete</button>    </li>  );} export default function Notes() {  return (    <ul>      <NoteRow        note={{ id: 7, title: "Order more matcha" }}        onOpen={(id) => console.log("Open note", id)}        onDelete={(id) => console.log("Delete note", id)}      />    </ul>  );}
          ResultLoading…

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 5 · ChallengeA search form that stays put

            On a real page, pressing Search would load a new page and throw the app away; here the preview catches the submit and says so in the console. Handle it yourself, so the preview has nothing to catch. Which call did you add?

            export default function TeaSearch() {  function handleSubmit(e) {    console.log("Searching for", e.currentTarget.elements.query.value);  }   return (    <form onSubmit={handleSubmit}>      <input name="query" aria-label="Search" defaultValue="chai" />      <button>Search</button>    </form>  );}
            ResultLoading…

            Answer, then press Check. Spacing and letter case don’t matter.

              Exercise 6 · ChallengeCount every click in a toolbar

              The toolbar should print clicked: Bold or clicked: Delete for every click, but Delete stops the click. Make the toolbar hear it anyway. What's the first line when you click Delete?

              export default function EditorToolbar() {  return (    <div onClick={() => console.log("toolbar clicked")}>      <button onClick={() => console.log("Bold")}>Bold</button>      <button        onClick={(e) => {          e.stopPropagation();          console.log("Delete");        }}      >        Delete      </button>    </div>  );}
              ResultLoading…

              Answer, then press Check. Spacing and letter case don’t matter.

                Check your understanding

                For order questions, trace the click: capture handlers from the outside in, then onClick from the clicked element out. Press Edit & run on a question's code and click to check.

                The responding to events quiz · 7 questionsScore: first tries count
                1. Question 1 of 7What happens when you click Save?

                  Read the code, then predictPop out in the code editor (opens in a new tab)JSX
                  export default function SaveButton() {
                    function save() {
                      console.log("Saved");
                    }
                    return <button onClick={save()}>Save</button>;
                  }

                  Choose an answer to see the explanation.

                2. Question 2 of 7In what order does the console show the letters after one click on Go?

                  Read the code, then predictPop out in the code editor (opens in a new tab)JSX
                  export default function Page() {
                    return (
                      <section onClickCapture={() => console.log("A")}>
                        <div onClick={() => console.log("B")}>
                          <button onClick={() => console.log("C")}>Go</button>
                        </div>
                      </section>
                    );
                  }

                  Choose an answer to see the explanation.

                3. Question 3 of 7A newsletter form reloads the page on submit, and your log disappears. Which call stops that?

                  Choose an answer to see the explanation.

                4. Question 4 of 7ProductCard is your own component, and it never reads a prop called onClick. What does <ProductCard onClick={handleClick} /> do on a click?

                  Choose an answer to see the explanation.

                5. Question 5 of 7What does this List print when you click Remove?

                  Read the code, then predictPop out in the code editor (opens in a new tab)JSX
                  export default function List() {
                    function handleClick(e) {
                      console.log(e.currentTarget.tagName);
                    }
                    return (
                      <ul onClick={handleClick}>
                        <li>
                          <button>Remove</button>
                        </li>
                      </ul>
                    );
                  }

                  Choose an answer to see the explanation.

                6. Question 6 of 7Which of these React events doesn't go up to the handlers of the elements around it?

                  Choose an answer to see the explanation.

                7. Question 7 of 7What is the e that React passes to your handler?

                  Choose an answer to see the explanation.

                Key takeaways

                • An event handler is a function you pass to a built-in element with a prop like onClick. React calls it when the event happens.
                • Pass the function, onClick={handleClick}, or an arrow function. handleClick() runs while rendering.
                • Handlers can be props. Name the props onSomething, after what happens in your app, and the functions handleSomething.
                • React passes an event object, e: its own, with the browser's in e.nativeEvent. e.target is what was clicked; e.currentTarget is where the handler sits.
                • Events go down through onClickCapture handlers, then bubble up through onClick handlers. e.stopPropagation() stops the trip up. onScroll doesn't bubble.
                • e.preventDefault() stops the browser's own action, like a form loading a new page.

                Remember the one-liner.
                Give React a function, not a call; the event bubbles up unless you stop it, and the browser acts unless you prevent it.

                Coming next: State: a component's memory. Your handlers will finally change what's on the screen.

                CompleteFrontend Clear concepts. Working examples.