sveltesveltekit

Svelte 5 custom dispatch Object literal may only specify known properties


I am trying to create a simple dispatcher but I keep getting error that it doesnt recognize the dispatcher that i am creating.

function dispatchChange() {
    dispatch('treeChange', {
        id: field.checkbox.id,
        selected: field.checkbox.selected,
        disabled: field.checkbox.disabled,
        visible: field.checkbox.visible
    });
}
<Checkbox 
    checked={item.field.checkbox.selected}
    onCheckedChange={() => dispatchChange()}
    aria-labelledby="terms-label"
/>

And here is how i am trying to use it

function handleCheckboxChange(event: CustomEvent) {
    const { id, selected, disabled, visible } = event.detail;
    console.log(`Checkbox ${id} in tree changed:`, { selected, disabled, visible });
    // Update your tree state here
}
<div on:treeChange={handleCheckboxChange}>

I keep getting:

Object literal may only specify known properties, and "on:treeChange" does not exist in type HTMLProps<"div", HTMLAttributes<any>>

And this:

Using on:treeChange to listen to the treeChange event is deprecated. Use the event attribute ontreeChange

I did try ontreeChange but doenst do anything, it still gets an error that its not recognized.


Solution

  • There are multiple issues. Most notably that events sent via the dispatcher do not bubble up the DOM tree and thus cannot be handled on elements. If you need this kind of functionality, you have to dispatch them as regular events to a specific element in the component.

    E.g.

    let root: HTMLElement = $state()!;
    
    function dispatchChange() {
      root.dispatchEvent(new CustomEvent("treeChange", {
        bubbles: true,
        detail: {
          // data here
        },
      }));
    }
    
    <div bind:this={root}>
      <Checkbox ... />
    </div>
    

    To make the on:treeChange not cause type errors, you need to extend the type definition for elements via a .d.ts file:

    import 'svelte/elements';
    
    declare module "svelte/elements" {
      export interface DOMAttributes<T extends EventTarget> {
        'on:treeChange'?: (event: CustomEvent<{/* detail properties */}>) => void;
        ontreeChange?: (event: CustomEvent<{/* detail properties */}>) => void;
      }
    }
    

    The second error refers to how in Svelte 5 events are just attributes/props with an on prefix. For components, functions should be passed directly rather than using the dispatcher. On the element both the old and new syntax should work in this case.

    But note that by dispatching directly to an element to have the event bubble up the DOM tree, you are circumventing the normal event mechanisms completely so the event cannot be handled on the component itself at all.