Skip to content

Feat: [Types] Improves "svelte/element" with directive-free types, and a configurable childrenΒ #13653

@adiguba

Description

@adiguba

Describe the problem

The module "svelte/elements" provides the definitions of HTML attributes that can be used to declare props to spread in a component that "wrap" a HTML element.

For example for a component Button, using directly the type HTMLButtonAttributes

<script lang="ts">
    import type { HTMLButtonAttributes } from 'svelte/elements';

    let { children, ...rest } : HTMLButtonAttributes = $props();
</script>

<button {...rest}>
    {@render children?.()}
</button>

Or via the equivalent using SvelteHTMLElements

<script lang="ts">
    import type { SvelteHTMLElements } from 'svelte/elements';

    let { children, ...rest } : SvelteHTMLElements['button'] = $props();
</script>

<button {...rest}>
    {@render children?.()}
</button>

But there are 2 flaws :

  • This include the definition of bind: and on: directives, which are therefore proposed by autocompletion
  • The children is defined with zero parameter, and this cannot be changed easily.

In order to remove the bind:/on: directives, II need to write something like that :

    let { children, ...rest } : Omit<HTMLButtonAttributes, `bind:${string}` | `on:${string}`> = $props();

And if I need to specify a parameter for the children snippet, I have to write :

    let { children, ...rest } : Omit<HTMLButtonAttributes, `bind:${string}` | `on:${string}` | 'children'>
        & { children?: Snippet<[number]> } = $props();

Describe the proposed solution

It would be nice if Svelte 5 had an official type to handle this in "svelte/elements".

Something like this might work :

export type SvelteHTMLProps<TagName extends string, Parameters extends unknown[] = []> = {
	children?: import('svelte').Snippet<Parameters>;
} & Omit<SvelteHTMLElements[TagName], `bind:${string}` | `on:${string}` | `children`>;

So we can use SvelteHTMLProps<'button'>in order to define our Button component :

<script lang="ts">
    import type { SvelteHTMLProps } from 'svelte/elements';

    let { children, ...rest } : SvelteHTMLProps<'button'> = $props();
</script>

<button {...rest}>
    {@render children?.()}
</button>

Or SvelteHTMLProps<'button', [number]>to define the children parameter type :

<script lang="ts">
    import type { SvelteHTMLProps } from 'svelte/elements';

    let { children, onclick, ...rest } : SvelteHTMLProps<'button', [number]> = $props();

    let count = $state(0);

    function countClick(evt) {
        count++;
        onclick?.(evt);
    }
</script>

<button onclick={countClick} {...rest}>
    {@render children?.(count)}
</button> 

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions