Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

thebigk's avatar
Level 13

AlpineJs Refuses To Work with Native HTML Event

Here's my simple AlpineJS code -

<div x-data="{show: true}">

<video src="..." onended="show=false"></video>

</div>

I'm wondering why is this not working? No error is thrown.

0 likes
14 replies
Sinnbeck's avatar

I dont think onended is a native alpine listener?

My guess would be

<video src="..." x-on:onended="show=false"></video>

or

<video src="..." @onended="show=false"></video>
thebigk's avatar
Level 13

Error with @onended="show=false" -

index.js:46 Uncaught DOMException: Failed to execute 'setAttribute' on 'Element': '@onended' is not a valid attribute name.
thebigk's avatar
Level 13

Interesting observation:

x-on:onended="alert('yo')"

This doesn't trigger! No error is thrown either. But if I go with @onended - it throws the above error. Something is fishy.

thebigk's avatar
Level 13

...and if I remove x-on or @, I do get an alert -

onended="alert('yo')"

This works.

Sinnbeck's avatar

@thebigk maybe you can call a function in plain Javascript that can interface with alpine (or livewire)?

thebigk's avatar
Level 13

@Snapey - MAN!!!!!!!!!!!!!!!!!!

x-on:ended="show=true"

What does onended do then?

This works perfectly! 3-hour long hair pulling and nervousness comes to an end.

kokoshneta's avatar

@thebigk The difference between ended and onEnded – or more generally, between someEvent and onSomeEvent – is that the former is the name of the event itself which is fired, whereas the latter is the name of the event listener attribute that can be added to an HTML element to tell the browser to execute specific code when the event is triggered or emitted. (They’re often called ‘event attributes’, but they define event listeners, not events, so personally, I think that’s a misnomer. The camelCasing is optional.)

Every event has an associated onXYZ event listener attribute which essentially functions as a more primitive, shorthand version of EventTarget.addEventListener(). So these two do roughly the same:

// HTML event listener attribute
<video id="vid" onEnded="alert('xyz')" />

// Manually defining event listener
el = document.getElementById('vid');
el.addEventListener("ended", function(event) {
	alert('xyz');
});

Plain JavaScript will automatically pick up on any standard event listener attributes you put on your elements, but remember that Alpine is not plain JavaScript – it doesn’t use the standard attributes for anything and doesn’t listen for them. Alpine only picks up and reacts to the x-attributes it defines, nothing else. That’s why you need to use x-on:ended (or the shorthand form @ended) to get Alpine to ‘see’ what you want it to do when the event is fired.

1 like
thebigk's avatar
Level 13

@kokoshneta Thank you for the explanation. If I understood you right; onended="key=value" should have worked; but it didn't. onended as a listener should have triggered the alpine variable change.

kokoshneta's avatar
Level 27

@thebigk No, onEnded (a ‘plain’ event listener attribute) is expected to contain plain JavaScript – that’s why onEnded="alert('xyz')" works. Technically, key=value is valid JavaScript, but it requires that you already have a plain JavaScript (not Alpine) variable called key and one called value. If you do, then it will set the value of key to be whatever the value of value is.

Alpine doesn’t use plain event listeners at all; it ignores them completely. It only uses its own special event listeners that begin with x-. Anything that interacts with Alpine must be in Alpine event listener attributes, not plain ones.

Take this as an example:

<video onEnded="var x = 5" x-on:ended="x = 5" />

When the video finishes playing, the browser will fire the ended event. That event will be caught by two different event listeners here:

  • the plain JavaScript listener will create a JavaScript variable called x in the global scope and set its value to 5
  • the Alpine listener will create or update a property called x on the JavaScript object that represents this particular Alpine component, and set its value to 5

So you will end up with two different variables called x: one is a global JavaScript variable in the window/document scope, and you can use any plain JavaScript to retrieve it (such as the console in your browser); the other is an object property belonging to the Alpine object that represents the component in which the video resides.

1 like

Please or to participate in this conversation.