Files
Devour/devour_data/docs/event-handlers.json
T
Tomas Dvorak 898a3c303f update
2026-02-24 10:33:59 +01:00

17 lines
11 KiB
JSON

{
"id": "61e64d2044027841b64733b0",
"source": "solid:signals",
"type": "github-document",
"title": "event-handlers",
"content": "---\ntitle: Event handlers\norder: 3\nuse_cases: \u003e-\n user interactions, click handling, form inputs, keyboard events, custom\n events, touch gestures, event optimization\ntags:\n - events\n - interactions\n - handlers\n - delegation\n - performance\n - dom\nversion: '1.0'\ndescription: \u003e-\n Handle user interactions in Solid with event delegation and native events for\n optimal performance and resource management.\n---\n\nEvent handlers are functions that are called in response to specific events occurring in the browser, such as when a user clicks or taps on an element.\n\nSolid provides two ways to add event listeners to the browser:\n\n- [`on:__`](/reference/jsx-attributes/on): adds an event listener to the `element`. This is also known as a _native event_.\n- [`on__`](/reference/jsx-attributes/on_): adds an event listener to the `document` and dispatches it to the `element`. This can be referred to as a _delegated event_.\n\nDelegated events conserve resources and improve performance for commonly used events by sharing a single handler.\nNative events, conversely, offer greater control over event behavior.\n\n## Using events\n\nTo add an event handler, prefix the event name with either `on` or `on:`, and assign it to the function you wish to call when the event is dispatched.\n\n```tsx\n// delegated event\n\u003cbutton onClick={handleClick}\u003eClick me\u003c/button\u003e\n\n// native event\n\u003cdiv on:scroll={handleScroll}\u003e... very long text ...\u003c/div\u003e\n```\n\nDelegated events are **not case sensitive**, therefore using delegated event handlers in Solid can be written using camelCase or all lowercase.\nNote that while delegated events can be written both ways, native events _are_ case sensitive.\n\n```tsx\n\u003cbutton onclick={handleClick}\u003eClick me\u003c/button\u003e\n```\n\nFor any other events, such as custom events or events you wish _not_ to be delegated, the `on:` attribute will add an event listener as-is.\nThis is what makes the event listener case sensitive.\n\n```tsx\n\u003cbutton on:Custom-Event={handleClick}\u003eClick me\u003c/button\u003e\n```\n\nFor typing standard or custom events using `on:`, the TypeScript page has a section about [event handlers](/configuration/typescript#event-handling).\n\n## Binding events\n\nTo optimize event handlers, you can pass an array as the event handler, replacing the function.\nWhen doing this, the second item passed into the array is supplied as the handler's first argument:\n\n```tsx\nconst handler = (data, event) =\u003e {\n\tconsole.log(\"Data:\", data, \"Event:\", event);\n};\n\n\u003cbutton onClick={[handler, \"Hello!\"]}\u003eClick Me\u003c/button\u003e;\n```\n\nIn this example, the `Hello!` string is passed as the `data` parameter in the `handler` function when the button is clicked.\n\nBy binding events in this way, Solid avoids the overhead of using JavaScript's [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) method and adding an additional closure.\n\n### Dynamic handlers\n\nAn event handler does not form part of the reactive system.\nIf you were to pass the handler as a signal, it will not respond to the changes of that signal.\nIn other words, events do not dynamically update, and the bindings are not reactive.\nThis is because attaching and detaching listeners is a resource-intensive task.\n\nSince event handlers are called like a standard function, you can design them to call a reactive source, if needed.\n\nIn the following example, `handleClick` represents a prop that has the flexibility to adopt any function.\nAs a result, there is no requirement for these functions to be reactive.\n\n```tsx\n\u003cdiv onClick={() =\u003e props.handleClick?.()} /\u003e\n```\n\n## Event delegation\n\nInstead of attaching event listeners to every individual element, Solid uses _synthetic event delegation_, through the [`on__`](/reference/jsx-attributes/on_) form .\nIn this method, event listeners are attached to the `document` element and dispatch events to the relevant elements as they bubble up.\n\nBy keeping the number of event listeners to a minimum, events can be captured more effectively.\nThis is especially useful when working with a large number of elements, such as in a table or list.\n\nSupported events such as `click`, `input` and `keydown` are just a few examples that are optimized in this way.\nTo view the full list see the [references below](#list-of-delegated-events).\n\nIf you need to attach an event listener to an element that is not supported by Solid's event delegation, such as a custom event in a [custom element](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements), you can use the [`on:__`](/reference/jsx-attributes/on) form.\n\n```tsx\n\u003cdiv on:customEvent={handleCustomEvent} /\u003e\n```\n\n### Event delegation considerations\n\nWhile delegated events provide some performance enhancements, there are tradeoffs.\n\nDelegated events flow through native element parents but can be overriden by components like Portal.\nThis can differ from the previous expectations of how events work and flow.\n\nSome things to keep in mind include:\n\n- Delegated event listeners are added _once_ per event type and handle all future events of that type.\nThis means that delegated event listeners remain active even if the element that added them and its handler is removed.\n For example, if a `div` listens for `mousemove` and is later removed, the `mousemove` events will still be dispatched to the `document` in case a different element is also listening for mouse moves.\n\n```tsx\n\u003cdiv onMouseMove={handleCustomEvent} /\u003e\n```\n\n:::tip[Occasional Events]\n\nRather than using delegated events for events that happen infrequently, **native events** are a better solution.\nSince these events happen in specific circumstances, they do not benefit from the performance improvements you get with event delegation.\n\n```tsx\n\u003cdiv on:mousemove={handleCustomEvent} /\u003e\n```\n\n:::\n\n- `event.stopPropagation()` does not work as expected since events are attached to the `document` rather than the `element`.\n\n With cases like this, a native event is recommended.\n As an example, using a native event would stop the following event from reaching the `div native` handler, which is _not_ the case for delegated events.\n You can [view this example in the Solid Playground](https://playground.solidjs.com/anonymous/c5346f84-01e4-4080-8ace-4443ffd0bb10).\n\n```tsx\nonMount(() =\u003e {\n\tref.addEventListener(\"click\", () =\u003e {\n\t\tconsole.log(\"div native\");\n\t});\n});\n\u003cdiv ref={ref}\u003e\n\t\u003cbutton\n\t\tonClick={(event) =\u003e {\n\t\t\tevent.stopPropagation();\n\t\t\tconsole.log(\"button\");\n\t\t}}\n\t\u003e\n\t\tbutton\n\t\u003c/button\u003e\n\u003c/div\u003e;\n```\n\n```shellsession title=\"Console output\"\n// Button clicked\ndiv native\nbutton\n```\n\nYou can solve this by switching the `button` event to using a native event:\n\n```tsx ins=\"on:click\"\n// ...\n\u003cbutton\n\ton:click={(event) =\u003e {\n\t\tevent.stopPropagation();\n\t\tconsole.log(\"button\");\n\t}}\n\u003e\n\tbutton\n\u003c/button\u003e\n// ...\n```\n\n```shellsession title=\"Console output\"\n// Button clicked\nbutton\n```\n\n[See how this solution differs in the Solid Playground](https://playground.solidjs.com/anonymous/9e2deddc-2e83-4ac2-8ee0-49c7c3a45d11).\n\n- [Portals](/concepts/control-flow/portal) propagate events following the _component tree_ and not the _DOM tree_, making them easier to use.\n This means when a `Portal` gets attached to the `body`, any events will propagate up to the `container`.\n\n```tsx\n\u003cdiv class=\"container\" onInput={() =\u003e console.log(\"portal key press\")}\u003e\n\t\u003cPortal mount={document.body}\u003e\n\t\t\u003cinput onInput={() =\u003e console.log(\"input key press\")} /\u003e\n\t\u003c/Portal\u003e\n\u003c/div\u003e\n```\n\n:::note[onInput / onChange]\n\n `onChange` and `onInput` events work according to their native behavior:\n - `onInput` will fire immediately after the value has changed\n - In `\u003cinput\u003e` fields, `onChange` will only fire after the field loses focus.\n\n:::\n\n### List of delegated events\n\nYou can also view this list in our [source code](https://github.com/ryansolid/dom-expressions/blob/main/packages/dom-expressions/src/constants.js) (see `DelegatedEvents`).\n\n- [`beforeinput`](https://developer.mozilla.org/en-US/docs/Web/API/Element/beforeinput_event)\n- [`click`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click)\n- [`dblclick`](https://developer.mozilla.org/en-US/docs/Web/API/Element/dblclick_event)\n- [`contextmenu`](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event)\n- [`focusin`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event)\n- [`focusout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusout_event)\n- [`input`](https://developer.mozilla.org/en-US/docs/Web/API/Element/input_event)\n- [`keydown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event)\n- [`keyup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/keyup_event)\n- [`mousedown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mousedown_event)\n- [`mousemove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mousemove_event)\n- [`mouseout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseout_event)\n- [`mouseover`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseover_event)\n- [`mouseup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseup_event)\n- [`pointerdown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerdown_event)\n- [`pointermove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event)\n- [`pointerout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerout_event)\n- [`pointerover`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerover_event)\n- [`pointerup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerup_event)\n- [`touchend`](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchend_event)\n- [`touchmove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchmove_event)\n- [`touchstart`](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchstart_event)",
"url": "https://github.com/solidjs/solid-docs/blob/HEAD/src/routes/concepts/components/event-handlers.mdx",
"metadata": {
"path": "src/routes/concepts/components/event-handlers.mdx",
"repo": "solidjs/solid-docs",
"repo_url": "https://github.com/solidjs/solid-docs.git",
"size": 9886,
"source_type": "github"
},
"hash": "eeaee12a38b9e752e336ce8446c60d75e4655c74cbaff6425cb2fb21612ab999",
"timestamp": "2026-02-23T11:43:00.186392173+01:00"
}