On This Page
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 thedeepkeyword.
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.deepis for piercing a shadow boundary — reaching into a child component’s internals. The two are different boundaries; default mode handles projection,deephandles 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
deeponly catches events dispatched withcomposed: true. Native events do; for custom events use the framework’sdispatchEvent, 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 usebind.
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.
| parameter | use |
|---|---|
| el | the component’s host element |
| target | the dom element that dispatched the event |
| event | the native event object |
| data | event.detail + data attributes on the dispatching element |
| value | value of the dispatching element (form fields, custom event detail) |
| isDeep | the 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— callsstopPropagation(), preventing the event from reaching other handlersreturn 'cancel'— callspreventDefault(), 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
attachEventwill automatically be removed when the component is destroyed usingabortController.
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 componentconst 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 }};