Events Using events with components grid Guide
Categories

Events

Inside Component

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();
}
}
});

Slotted Content Default selectors match content slotted into your component too. If your template has a <slot> and a user places a <ui-button> inside, 'click ui-button' fires without ceremony — the slotted child is part of your component’s logical template. To reach inside another web component’s shadow tree, use the deep keyword.

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

Pass an event name without a selector to fire on any part of the component, including the host’s own surface and host-dispatched events.

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

Inside Templates

@Event Handler

You can bind events directly from inside templates using @event syntax. You can specify the handler using an expression that points to any function, like a setting, or template method.

<div @click={doSomething}></div>

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

Use the global keyword to attach an event to an element outside your component.

const events = {
'global scroll'() {
// no selector binds to window
},
'global click body'() {
// any click on the body
}
};

Deep Events

You can use the deep keyword to attach events to elements inside another web component’s shadow DOM. Without deep, selectors only match content reachable from your component’s template — including slotted children — but not the internal DOM of nested components.

Projection vs. Piercing Slotted content is projected through your <slot>s and matches default selectors automatically. deep is for piercing a shadow boundary — reaching into a child component’s internals. The two are different boundaries; default mode handles projection, deep handles piercing.

<div class="component">
<ui-button>Submit</ui-button>
</div>
const events = {
'deep ui-button .icon'() {
// .icon lives inside ui-button's shadow tree
}
};

Composed events deep only catches events dispatched with composed: true. Native events do; for custom events use the framework’s dispatchEvent, which sets it by default.

Bound events

You can use the bind keyword to attach an event directly to matching selectors instead of using an event delegation pattern.

Event handling in Semantic uses event delegation, which assigns event handlers to the shadow root.

This is helpful to allow the events to continue to fire even if an element is added or removed from the DOM matching a selector, but may not be ideal in all cases.

Some web components use new CustomEvent() which unlike most native events do not bubble by default. To attach events to these components you may need to use bind.

const events = {
'bind customevent some-component'() {
// customevent fired on some-component
}
};

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 component’s host element
targetthe dom element that dispatched the event
eventthe native event object
dataevent.detail + data attributes on the dispatching element
valuevalue of the dispatching element (form fields, custom event detail)
isDeepthe event came from inside another web component’s shadow tree

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

Handler Return Values

Event handlers support special return values to control propagation:

  • return false — calls stopPropagation(), preventing the event from reaching other handlers
  • return 'cancel' — calls preventDefault(), canceling the browser’s default action
const events = {
'click .item'({ event }) {
return false; // stops propagation
},
'submit form'({ event }) {
return 'cancel'; // prevents default
}
};

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 abortController.

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 defaultSettings = {
// 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. 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
}
};
Previous
State
Next
Reactivity