Events Usings events with components grid Guide

Events

Binding Event Handlers

Semantic components can include events by passing in an object mapping events to event handlers when creating your component. Events take the form of eventName selector, for instance click .submit.

See below for an example of how this works.

Event Delegation Event handlers are attached to the shadow root of your component using a pattern called event delegation where the component listens for the bubbled event. This means that even if you add or remove content that matches the selector after render the event will still fire if the selector matches.

defineComponent({
events: {
'click .submit'({ self }) {
self.submit();
},
'click .menu ui-button'({ self }) {
self.doSomething();
}
}
});

Multiple Events + One Selector

You can specify multiple events using a comma separated list with a single selector.

This example binds mouseup and mouseleave to .selector

const events = {
'mouseup, mouseleave .selector'({state}) => {
state.active.set(false);
}
};

Multiple Events + Multiple Selectors

You can also specify multiple selectors when specifying an event by passing in a comma separated list.

This example binds click to .selector1 and .selector2

const events = {
'click .selector1, click .selector2' () => {
// do something
}
};

Component-Wide Events

To attach events to your entire component you can pass in an event name without a selector.

For example if you have a component called ui-button this would fire when the mouse hovered over any part of the component.

const events = {
'mouseover'({state}) => {
state.hovered.set(true);
}
'mouseout'({state}) => {
state.hovered.set(false);
}
};

Special Event Bindings

You can add special keywords to that modify how events are attached permitting you to bind events to elements other than those found in your component’s template.

Global Events

You can use the global keyword to attach an event globally to any element outside of your component.

For instance this can be used with global events like scroll or hashchange

const events = {
'global scroll window'() => {
// page scrolled
}
};

Deep Events

You can use the deep keyword to attach events to nested web components or slotted content. This can let you target parts of the component’s shadow DOM or slotted content which a person using your component might include.

Deep Usage - By default selectors will only match the DOM of your component’s template. This will prevent the handler from firing if the user slots content which also matches your selectors.

<div class="component">
<ui-button>Submit</ui-button>
</div>
const events = {
'deep ui-button .icon'() => {
// the icon is part of `ui-button` shadow DOM
}
};

Event Arguments

In addition to the standard arguments that are passed to all component callbacks, event handlers get access to a few extra arguments.

parameteruse
elthe dom element that dispatched the event
eventthe native event object
dataevent.detail + data attributes on dom element
isDeepthe event occurred on a nested web component or slot

In the following example events are attached to four separate buttons to control the size of the shape accessing methods using self.

Event Data

In many cases you want to access data particular to an event. Event handlers can use data to achieve this.

HTML Metadata

HTML metadata can be added using data attributes and will be available directly from the data object

<div class="increment" data-amount="1">Increment 1</div>
<div class="increment" data-amount="10">Increment 10</div>
const events = {
'click .increment'({self, data]}) {
self.increment(data.amount);
}
};

Custom Event Data

Any custom event metadata will also be available in the data attribute.

Another component creates an event

const createComponent = ({dispatchEvent}) {
startResize() {
dispatchEvent('resizeStart', {
startPosition: currentPosition,
});
}
}

Your component’s listens to the event

const events = {
'resizeStart custom-component'({data}) {
// data is { startPosition }
},
};

Data Example

In the following example html data attributes control whether the width or height is mutated and whether it is growing or shrinking.

Advanced Use Cases

In some scenarios you may want to manually bind and unbind events that are part of your components lifecycle.

Binding Events Dynamically

You can use attachEvent which is passed to all component callbacks to attach events dynamically where you may not know the selector until the component is created

All events attached with attachEvent will automatically be removed when the component is destroyed using abortSignals.

const onCreated = ({attachEvent, settings, isClient}) => {
if(isClient) {
attachEvent(settings.scrollContext, 'scroll', self.onPageScroll)
}
};

Manually Removing Events

When you use attachEvent it will return an event handler that you can use to unbind an event later using off

const onCreated = ({attachEvent, $, isClient}) => {
const handler = attachEvent('body', 'click', () => {
console.log('You clicked me');
})
$('body').off('click', handler)
};

Creating Events

Dispatching Custom Events

Custom events can be emitted from your component using dispatchEvent and can include custom metadata which will be passed along as data to events.

const createComponent = ({dispatchEvent}) => {
scrollToItem(itemID) {
// handle scrolling to item
dispatchEvent('itemactive', { itemID, position });
},
};

Callbacks versus events Although you can use callback functions in component settings to alert of internal changes in a component, it is a better pattern to only use callbacks in settings if you need the function to return a value as dispatched events cannot achieve this.

const settings = {
// this could be useful to allow user to cancel an internal action
shouldShow: () => true,
// this should probably be a custom event
onShow: function(){},
};

Listening to Custom Events

You can listen to a custom event the same way as a normal browser event, however they can include additional metadata.

// from another component
const events = {
'itemactive inpage-menu'({self, data}) {
const { itemID, position } = data;
// do something with metadata
}
};

You can also use query to listen to custom events from your component

import { $ } from '@semantic-ui/query';
$('inpage-menu', 'itemactive', (event) => {
const { itemID, position } = event.details;
// do something with metadata
})

Or simply use vanilla javascript

const el = document.querySelector('inpage-menu');
el.addEventListener('itemactive', (event) => {
const { itemID, position } = event.details;
});

Built In Events

Lifecycle Events

You can listen to any components lifecycle events with event listeners similar to Components all emit lifecycle events as native DOM events that can be used to respond to the lifecycle of subcomponents.

The custom event will also include a reference to the component which you can use to invoke behaviors on that component.

const events = {
'rendered inpage-menu'({self, data}) {
// component lifecycle event passes through component instance at data
const menu = data.component;
menu.setActive();
}
'destroyed inpage-menu'() {
// menu component is destroyed
}
};