JavaScript Element transitionend Event

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
DOM event
Instance event

What You’ll Learn

The transitionend event fires when a CSS transition completes. Learn addEventListener vs ontransitionend, TransitionEvent properties, both-direction finishes, when the event is skipped, how it pairs with transitioncancel, and five try-it labs.

01

Kind

Instance event

02

Type

TransitionEvent

03

When

Transition finished

04

Handler

ontransitionend

05

Cancelable?

No

06

Status

Baseline Widely

Introduction

When a CSS transition runs to completion, the browser fires transitionend. Use it to run cleanup or follow-up work only after the motion is done—hide a panel, unlock a button, or chain the next animation.

It fires in both directions: when the element finishes moving to the transitioned state, and when it fully reverts to the default state. If the transition is aborted early, you get transitioncancel instead—and transitionend will not fire for that transition.

💡
Beginner tip

Multiple CSS properties can each produce their own transitionend. Check event.propertyName when you only care about one property (for example opacity).

Understanding transitionend

An instance event on elements that participate in CSS Transitions. MDN: it fires when a CSS transition has completed. It is not cancelable.

  • Completes in both directions—to the new state and back to the default.
  • TransitionEvent — includes propertyName, elapsedTime, pseudoElement.
  • Skipped if the transition is removed early (display: none, clear transition-property) or canceled.
  • Baseline Widely available — solid modern browser support (since Oct 2018).

📝 Syntax

Use the event name with addEventListener, or set the handler property:

JavaScript
addEventListener("transitionend", (event) => { });

ontransitionend = (event) => { };

Event type

A TransitionEvent (inherits from Event).

Event properties

PropertyMeaning
propertyNameThe CSS property name associated with the transition
elapsedTimeSeconds the transition had been running when the event fired (not affected by transition-delay)
pseudoElement:: name if the transition runs on a pseudo-element; otherwise ""

⚖️ Transition lifecycle events

EventWhen it firesTypical use
transitionrunTransition is created (may still be in delay)Know a transition was scheduled
transitionstartTransition actually starts animating (after delay)Mark UI as “in motion”
transitionendTransition finishes normally (both directions)Cleanup after success
transitioncancelTransition is aborted earlyCleanup after interrupt

MDN notes: if there is no delay or duration (both 0s or undeclared), there is no transition—and none of these events fire. If transitioncancel fires, transitionend will not.

⚡ Quick Reference

GoalCode
Listenel.addEventListener("transitionend", fn)
Handler propertyel.ontransitionend = fn
Filter one propertyif (event.propertyName === "opacity") { ... }
Read timeevent.elapsedTime
Cancelable?No
MDN statusBaseline Widely available

🔍 At a Glance

Four facts to remember about transitionend.

Event type
TransitionEvent

Property + time

Means
finished

Both directions

Cancelable
false

Observe only

Baseline
yes

Widely available

Examples Gallery

Examples follow MDN Element: transitionend event. Try It Yourself labs let a CSS transition finish so you can see the event fire.

📚 Getting Started

Register handlers the MDN ways, then let the transition finish.

Example 1 — addEventListener("transitionend")

MDN: listen on a transitioning element and wait until it completes.

JavaScript
const box = document.querySelector(".transition");

box.addEventListener("transitionend", () => {
  console.log("Transition ended");
});

// Start the transition and let it finish:
box.classList.add("grown");
Try It Yourself

How It Works

Adding the driving class starts the CSS transition. When it reaches the end state, the browser fires transitionend (once per transitioned property).

Example 2 — ontransitionend Property

MDN’s alternate style using the event handler property.

JavaScript
const box = document.querySelector(".transition");

box.ontransitionend = () => {
  console.log("Transition ended");
};

box.classList.add("grown");
Try It Yourself

How It Works

Same event, different registration API. Prefer addEventListener when you need multiple listeners or easy removal.

📈 Details, Filter & Lifecycle

Read TransitionEvent fields, filter by property, watch the full set.

Example 3 — Read propertyName and elapsedTime

Use TransitionEvent properties for logging or debugging.

JavaScript
const box = document.getElementById("box");

box.addEventListener("transitionend", (event) => {
  console.log("ended:", event.propertyName);
  console.log("elapsedTime:", event.elapsedTime);
  console.log("pseudoElement:", JSON.stringify(event.pseudoElement));
});

box.classList.add("grown");
Try It Yourself

How It Works

elapsedTime is how long the transition had been running (in seconds) when end fired. MDN notes it is not affected by transition-delay.

Example 4 — Filter by propertyName

Only react when a specific property finishes (ignore the others).

JavaScript
const box = document.getElementById("box");
const out = document.getElementById("out");

box.addEventListener("transitionend", (event) => {
  if (event.propertyName !== "opacity") return;
  out.textContent = "Opacity transition finished";
});

box.classList.add("grown");
Try It Yourself

How It Works

When several properties transition together, each one can fire transitionend. Filtering avoids running cleanup twice.

Example 5 — Full Lifecycle Log

Inspired by MDN’s live example: log run, start, cancel, and end together.

JavaScript
const el = document.querySelector(".transition");
const message = document.querySelector(".message");
const btn = document.getElementById("toggle");

el.addEventListener("transitionrun", () => {
  message.textContent = "transitionrun fired";
});
el.addEventListener("transitionstart", () => {
  message.textContent = "transitionstart fired";
});
el.addEventListener("transitioncancel", () => {
  message.textContent = "transitioncancel fired";
});
el.addEventListener("transitionend", () => {
  message.textContent = "transitionend fired";
});

btn.addEventListener("click", () => {
  el.classList.toggle("grown");
});
Try It Yourself

How It Works

Toggle the class on and wait for the duration to see transitionend. Toggle it off mid-flight to see transitioncancel instead. MDN’s hover demo works the same way—stay hovered until the end.

🚀 Common Use Cases

  • Removing a modal from the DOM only after its fade-out finishes.
  • Unlocking buttons or focus after an entrance transition completes.
  • Chaining a second motion only after the first property finishes.
  • Analytics that distinguish finished vs canceled transitions.
  • Teaching the full CSS transition event set alongside transitioncancel.

🔧 How It Works

1

Transition is created

transitionrun fires; transitionstart follows after any delay.

Schedule
2

Properties animate to the end

The transition runs for its full duration without being removed or reversed early.

Play
3

Browser fires transitionend

A TransitionEvent is dispatched per finished property (not cancelable).

Event
4

Your handler cleans up

Remove nodes, unlock UI, or start the next step after a successful finish.

📝 Notes

  • MDN: Baseline Widely available (since October 2018).
  • Not Deprecated, Experimental, or Non-standard — no status banner required.
  • Fires in both directions; filter with propertyName when needed.
  • If transitioncancel fires, transitionend will not fire for that transition.
  • Related learning: transitioncancel, animationend, addEventListener(), JavaScript hub.

Browser Support

transitionend is marked Baseline Widely available on MDN (across browsers since October 2018). Logos use the shared browser-image-sprite.png sprite from this project.

Baseline · Widely available

Element transitionend

Fires when a CSS transition completes; TransitionEvent exposes propertyName, elapsedTime, and pseudoElement. Not cancelable.

Full Widely available
Google Chrome 26+ (standard name)
Yes
Mozilla Firefox 51+
Yes
Apple Safari 7+ (standard name)
Yes
Microsoft Edge 18+ / Chromium
Yes
Opera 12.1+
Yes
Internet Explorer 10–11 (partial)
Partial
transitionend Baseline

Bottom line: Listen with addEventListener("transitionend", …), filter by propertyName when several properties finish, and pair with transitioncancel for interrupted paths.

Conclusion

transitionend tells you a CSS transition finished normally—in either direction. Listen with addEventListener, read TransitionEvent details when you need them, and handle transitioncancel for interrupted paths.

Continue with transitionrun, transitioncancel, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Use addEventListener("transitionend", ...)
  • Filter with event.propertyName when multiple properties transition
  • Also listen for transitioncancel if cleanup must always run
  • Give transitions a real duration/delay when you expect events
  • Keep end handlers light and idempotent

❌ Don’t

  • Assume every transition stop fires transitionend
  • Expect events when duration and delay are both 0s
  • Hide with display: none mid-flight and still expect transitionend
  • Forget both-direction finishes (open and close)
  • Confuse CSS Transitions with CSS Animations / Web Animations

Key Takeaways

Knowledge Unlocked

Five things to remember about transitionend

CSS transition finished—safe time for cleanup and next steps.

5
Core concepts
🎨 02

TransitionEvent

property + time

API
🔁 03

Both ways

to & from

Direction
🔔 04

addEventListener

preferred

Listen
🎯 05

Baseline

widely available

Compat

❓ Frequently Asked Questions

It fires when a CSS transition has completed — both when finishing toward the transitioned state and when fully reverting to the default state. It is not cancelable.
No. MDN does not mark Element transitionend as Deprecated, Experimental, or Non-standard. It is Baseline Widely available (across browsers since October 2018).
A TransitionEvent. Useful read-only properties include propertyName, elapsedTime, and pseudoElement.
Prefer element.addEventListener("transitionend", handler). You can also set ontransitionend where supported.
transitionend fires when the transition finishes normally. transitioncancel fires when it is aborted early. If transitioncancel fires, transitionend will not fire for that transition.
If the transition is removed before completion (for example transition-property is cleared or display is set to none), or if transitioncancel fires, or if delay and duration are both 0s / undeclared so there is no transition.
Did you know?

Leaving a hover mid-flight cancels the transition ( transitioncancel). Staying until the motion finishes gives you transitionend—and the same event fires again when the box fully reverts after you leave.

Next: transitionrun

Learn when a CSS transition is first created (before delay).

transitionrun →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful