Skip to content

Auto-options

HTML attributes are strings. Svelte props can be strings, numbers, booleans, arrays, or objects. Custom element prop metadata is what connects those two worlds.

@svebcomponents/auto-options generates that metadata from the TypeScript types you already write in $props().

In Svelte 5, props usually live in $props():

<script lang="ts">
interface Props {
label: string;
value: number;
featured: boolean;
}
let { label, value, featured }: Props = $props();
</script>

Before the Svelte compiler runs, auto-options reads this declaration and generates the equivalent custom element options:

<svelte:options
customElement={{
props: {
label: { attribute: "label", reflect: true, type: "String" },
value: { attribute: "value", reflect: true, type: "Number" },
featured: { attribute: "featured", reflect: true, type: "Boolean" },
},
}}
/>

When you build with @svebcomponents/build, this transform is already part of the pipeline.

Write the custom element’s tag with Svelte’s own string-shorthand syntax:

<svelte:options customElement="favorite-number" />

auto-options expands this into the object form shown above, merging in the inferred props — you get the tag declaration and the prop metadata from a single line. The object form (customElement={{ tag: "favorite-number" }}) works identically; use it directly when you also need shadow or a manual extend.

JavaScript prop names remain camel-cased while their HTML attributes are kebab-cased:

Prop nameAttribute name
valuevalue
favoriteNumberfavorite-number
isFeaturedis-featured

This lets component code use normal JavaScript naming while consumers get HTML-shaped markup.

With generated metadata, Svelte can convert incoming attributes to the corresponding prop types:

<favorite-number value="42" featured="true"></favorite-number>

Here, value can become a number and featured can become a boolean instead of both remaining strings.

There is one interop detail worth keeping close at hand.

When a Svelte app consumes a custom element, pass non-string values as JavaScript expressions:

<favorite-number value={42}></favorite-number>

This passes the number 42.

<favorite-number value="42"></favorite-number>

Under certain conditions, Svelte assigns this value directly to the JavaScript property. In that case the value is the string "42" and the custom element’s attribute converter is bypassed.

Inference should remove boilerplate without removing control. You can provide custom element prop options manually when you need a different attribute name, type, or reflection behavior:

<svelte:options
customElement={{
props: {
value: { type: "Number", attribute: "data-value", reflect: false },
},
}}
/>

auto-options preserves fields you wrote manually and fills in missing props and fields where it can.

For supported prop shapes, inferred types, standalone plugin setup, and current limitations, see the @svebcomponents/auto-options reference.