diff --git a/CHANGELOG.md b/CHANGELOG.md
index 947173fd4d..0b2bb5d7fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
* Return the context object in `setContext` [#7427](https://github.com/sveltejs/svelte/issues/7427)
* Fix `{@const}` tag not working inside Component when there's no `let:` [#7189](https://github.com/sveltejs/svelte/issues/7189)
* Ignore comments in `{#each}` blocks when containing elements with `animate:` ([#3999](https://github.com/sveltejs/svelte/issues/3999))
+* Add a third parameter to the returned function of `createEventDispatcher` that allows passing an object of `{ cancelable: true }` to create a cancelable custom event. The returned function when called will also return a boolean depending on whether the event is cancelled ([#7064](https://github.com/sveltejs/svelte/pull/7064))
## 3.47.0
diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md
index a0d3f4148c..c6423f408c 100644
--- a/site/content/docs/03-run-time.md
+++ b/site/content/docs/03-run-time.md
@@ -221,14 +221,14 @@ Retrieves the whole context map that belongs to the closest parent component. Mu
#### `createEventDispatcher`
```js
-dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();
+dispatch: ((name: string, detail?: any, options?: DispatchOptions) => boolean) = createEventDispatcher();
```
---
Creates an event dispatcher that can be used to dispatch [component events](/docs#template-syntax-component-directives-on-eventname). Event dispatchers are functions that can take two arguments: `name` and `detail`.
-Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data.
+Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture). The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data.
```sv
+```
+
### `svelte/store`
The `svelte/store` module exports functions for creating [readable](/docs#run-time-svelte-store-readable), [writable](/docs#run-time-svelte-store-writable) and [derived](/docs#run-time-svelte-store-derived) stores.
diff --git a/src/runtime/internal/dev.ts b/src/runtime/internal/dev.ts
index 4501771c0a..0ba47f7e86 100644
--- a/src/runtime/internal/dev.ts
+++ b/src/runtime/internal/dev.ts
@@ -2,7 +2,7 @@ import { custom_event, append, append_hydration, insert, insert_hydration, detac
import { SvelteComponent } from './Component';
export function dispatch_dev(type: string, detail?: T) {
- document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail }, true));
+ document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail }, { bubbles: true }));
}
export function append_dev(target: Node, node: Node) {
diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts
index 287c16b5fc..e2a7420236 100644
--- a/src/runtime/internal/dom.ts
+++ b/src/runtime/internal/dom.ts
@@ -634,9 +634,9 @@ export function toggle_class(element, name, toggle) {
element.classList[toggle ? 'add' : 'remove'](name);
}
-export function custom_event(type: string, detail?: T, bubbles: boolean = false) {
+export function custom_event(type: string, detail?: T, { bubbles = false, cancelable = false } = {}): CustomEvent {
const e: CustomEvent = document.createEvent('CustomEvent');
- e.initCustomEvent(type, bubbles, false, detail);
+ e.initCustomEvent(type, bubbles, cancelable, detail);
return e;
}
diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts
index 3b3c2f5f71..fbbeca9a67 100644
--- a/src/runtime/internal/lifecycle.ts
+++ b/src/runtime/internal/lifecycle.ts
@@ -27,22 +27,33 @@ export function onDestroy(fn: () => any) {
get_current_component().$$.on_destroy.push(fn);
}
-export function createEventDispatcher<
- EventMap extends {} = any
->(): >(type: EventKey, detail?: EventMap[EventKey]) => void {
+export interface DispatchOptions {
+ cancelable?: boolean;
+}
+
+export function createEventDispatcher(): <
+ EventKey extends Extract
+>(
+ type: EventKey,
+ detail?: EventMap[EventKey],
+ options?: DispatchOptions
+) => boolean {
const component = get_current_component();
- return (type: string, detail?: any) => {
+ return (type: string, detail?: any, { cancelable = false } = {}): boolean => {
const callbacks = component.$$.callbacks[type];
if (callbacks) {
// TODO are there situations where events could be dispatched
// in a server (non-DOM) environment?
- const event = custom_event(type, detail);
+ const event = custom_event(type, detail, { cancelable });
callbacks.slice().forEach(fn => {
fn.call(component, event);
});
+ return !event.defaultPrevented;
}
+
+ return true;
};
}