
Enter a search term above to see results...
Enter a search term above to see results...
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(); } }});
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); }};
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 }};
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); }};
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.
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 }};
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 }};
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 dom element that dispatched the event |
event | the native event object |
data | event.detail + data attributes on dom element |
isDeep | the 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
.
In many cases you want to access data particular to an event. Event handlers can use data
to achieve this.
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); }};
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 } },};
In the following example html data attributes control whether the width or height is mutated and whether it is growing or shrinking.
In some scenarios you may want to manually bind and unbind events that are part of your components lifecycle.
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 usingabortSignals
.
const onCreated = ({attachEvent, settings, isClient}) => { if(isClient) { attachEvent(settings.scrollContext, 'scroll', self.onPageScroll) }};
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)};
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(){},};
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;});
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 }};