cferdinandi / reef

A lightweight library for creating reactive, state-based components and UI.

Home Page:https://reefjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Events for component

mouse0270 opened this issue · comments

What is the best way to add an onclick event for elements created in a component. In older versions you had the option of listeners but I am not sure what the option is now if one eve exists.

To be more clear. My code is loaded inside a ES Module.

component('taskbar icons', () => {
	return `<icon><i class="fa-brands fa-windows"></i></icon>
	${Object.entries(TASKBAR.#ICONS).map(([key, value]) => {
		return `<icon data-id="${value.id}" onclick="iconClick();"><i class="${value.icon}"></i> ${value.label ?? ''}</icon>`
	})}`
}, { events: true });

And it appears that because of this the onclick event can't be reached unless I define it outside of my module... Which kinda defeats the whole purpose of developing an es module.

You have a few options.

One (my preferred method) is to use event delegation.

component('taskbar icons', () => {
	return `<icon><i class="fa-brands fa-windows"></i></icon>
	${Object.entries(TASKBAR.#ICONS).map(([key, value]) => {
		return `<icon data-id="${value.id}"><i class="${value.icon}"></i> ${value.label ?? ''}</icon>`
	})}`
});

document.addEventListener('click', function (event) {

    // Only run on our target elements
    if (!event.target.matches('icon[data-id]') return;
    
    // Do stuff...
    
});

Alternatively, you can include your event handler inside the ES module.

function onClick () {
    // Do stuff...
}

component('taskbar icons', () => {
	return `<icon><i class="fa-brands fa-windows"></i></icon>
	${Object.entries(TASKBAR.#ICONS).map(([key, value]) => {
		return `<icon data-id="${value.id}" onclick="iconClick();"><i class="${value.icon}"></i> ${value.label ?? ''}</icon>`
	})}`
}, { events: true });

And it appears that because of this the onclick event can't be reached unless I define it outside of my module... Which kinda defeats the whole purpose of developing an es module.

I'm not sure I follow. If you include it in the module and import that module, the function should be available as a side-effect. I can't speak to your specific build setup, though.

As an aside, you shouldn't attach click handlers to non-focusable elements.

In the example above, icon is not a focusable element, and thus can never be reached by keyboard users. Additionally, folks who use a screen reader will not know it's an interactive element.

So I ended up basically going with event delegation, because I was doing what you did in your second example and that was not working

function iconClick() {
	MODULE.log('hello World');
}

component('taskbar icons', () => {
	return `<icon><i class="fa-brands fa-windows"></i></icon>
	${Object.entries(TASKBAR.#ICONS).map(([key, value]) => {
		return `<icon key="${value.id}" onclick="iconClick();"><i class="${value.icon}"></i> ${value.label ?? ''}</icon>`
	})}`
}, { events: true });

This does not work for me, I get the error
image

As for the non-focusable elements issue. this is being used in a virtual tabletop application... Basically, if you're blind you can't use the app anyways. So accessibility is not really a concern for this specific use case, but thank you for letting me know.

this is being used in a virtual tabletop application... Basically, if you're blind you can't use the app anyways.

I cannot understate how bad and objectively wrong this response it.

You absolutely can build VTT's accessibly, accessibility is always a concern, not building it accessibly is likely a violation of the ADA, and you're not fulfilling your professional obligations as a web developer.

I am not the creator of the program. Switching the elements over only temporarily solves the issue as it still requires you to click on one of the buttons before you can tab over to the next one.

Hitting the tab before you've clicked on a button will never get you to the buttons.