Skip to content

Consumer types

svebcomponents writes framework-neutral declarations beside each browser entry. It writes a separate Svelte template augmentation. React and Vue projects compose the exported interfaces in one project declaration file.

A component declaration can contain five public interfaces. svebcomponents omits empty interfaces.

InterfaceSurface
SimpleComponentElementDOM properties and typed addEventListener overloads
SimpleComponentEventMapEvent names mapped to CustomEvent<Detail>
SimpleComponentAttributesMarkup attribute names and values
SimpleComponentPropsProperty names that need their JavaScript values
SimpleComponentEventHandlersonchange-style handler properties

The main declaration augments HTMLElementTagNameMap. Import the component entry, then use standard DOM APIs:

import "my-components";
const element = document.querySelector("simple-component");
element?.count; // number | undefined
element?.addEventListener("change", (event) => {
event.detail; // generated detail type
});

document.createElement("simple-component") returns the same element type.

The build writes a svelte/elements augmentation beside the main declaration:

dist/client/SimpleComponent.svelte-types.d.ts

svebcomponents references this file from the main declaration if your package lists Svelte as a dependency or required peer dependency. Svelte consumers need no project setup in that case.

A framework-neutral package can expose the augmentation as a type-only export:

{
"exports": {
"./svelte": {
"types": "./dist/client/SimpleComponent.svelte-types.d.ts"
}
}
}

The consuming Svelte project imports it from a declaration file:

src/app.d.ts
import "my-components/svelte";

React 19 assigns rich values to matching custom-element properties and handles custom events. Add this augmentation to the consuming project:

import type { DetailedHTMLProps, HTMLAttributes } from "react";
import type {
SimpleComponentElement,
SimpleComponentAttributes,
SimpleComponentProps,
SimpleComponentEventHandlers,
} from "my-components";
declare module "react" {
namespace JSX {
interface IntrinsicElements {
"simple-component": DetailedHTMLProps<
HTMLAttributes<SimpleComponentElement>,
SimpleComponentElement
> &
SimpleComponentAttributes &
SimpleComponentProps &
SimpleComponentEventHandlers;
}
}
}

Vue’s template checker reads $props and $emit from a component-like type:

import type { HTMLAttributes, PublicProps } from "vue";
import type {
SimpleComponentElement,
SimpleComponentAttributes,
SimpleComponentProps,
SimpleComponentEventMap,
} from "my-components";
type DefineCustomElement<
ElementType extends HTMLElement,
Events extends Record<string, Event>,
Attributes,
Props,
> = new () => ElementType & {
$props: HTMLAttributes & Partial<Attributes> & Partial<Props> & PublicProps;
$emit: <K extends keyof Events>(event: K, payload: Events[K]) => void;
};
declare module "vue" {
interface GlobalComponents {
"simple-component": DefineCustomElement<
SimpleComponentElement,
SimpleComponentEventMap,
SimpleComponentAttributes,
SimpleComponentProps
>;
}
}

An HTML attribute carries a string. Svelte, React 19, and Vue can assign a JavaScript value to a property that shares the attribute name. SimpleComponentAttributes accepts that property type and its string form.

Kebab-case attributes cannot preserve objects or arrays. Pass those values with the camelCase property name from SimpleComponentProps:

<simple-component preloadedData={value}></simple-component>

Function and snippet props stay on SimpleComponentElement. Template syntax interprets onSelect={fn} as an event handler, so set a function prop through a DOM reference:

const element = document.querySelector("simple-component");
if (element) element.onSelect = handleSelect;

React 18 stringifies custom-element props and does not attach listeners for custom event names. Use React 19 with the augmentation above.

Svelte’s SvelteHTMLElements interface contains a catch-all index signature. Svelte checks attributes on declared elements. Its index signature accepts arbitrary attributes on an undeclared tag.

Put each augmentation in a .d.ts file or another module that the project’s tsconfig.json includes.