This is a custom elements library that can in theory be used anywhere that supports html and javascript, this applies to web applications created with frameworks other than Svelte as long as they support custom elements. This includes React 19+, Angular, Vue, and even plain html with javascript.
Example custom component, note the svelte:options element at the top that defines the custom element name as well as any name changes for its attributes as well as type definitions.
<svelte:options
customElement={{
tag: "ui-counter",
props: {
// rename startCount to start-count when used in consuming app
startCount: { attribute: 'start-count', type: 'Number'},
// set 'step' to a type 'Number' vs default String typing
step: { attribute: 'step', type: 'Number'}
}
}}
/>
<script lang="ts">
let {startCount = 0, step = 1} = $props();
let count: number = $derived(startCount)
const increment = () => {
count += step;
}
</script>
<button onclick={increment}>
count is {count}
</button>
// ...See the Svelte Custom Elements documentation page for more information.
- use the
svelte:optionstag to define the custom element tag name and props.- Custom Elements must have a - (dash) in the name, i.e. my-element
- see Custom Elements for more information
- prop/attribute names must be converted to kebab-case, i.e. "startCount" to "start-count"
- valid property types in the
svelte:optionsprops object are 'String', 'Number', 'Boolean', 'Array', and 'Object'.
- an import entry must be added to the
src/index.tsfile, i.e. for the Counter component the entry is:import './lib/Counter.svelte';, this triggers compilation of the component to a custom web element. - define the custom element by its registered name in two places inside the
src/custom-elements.d.ts fileto define its attribute/prop types used by consuming applications depending on type. Use the registered attribute names to do this, i.e.start-countinside theCountercomponent, and notstartCountwhich is used inside the Svelte code
Storybook is currently setup to test custom web elements (NOT Svelte components), so what we see by executing storybook right now is the custom element as it appears after the build step, not a svelte component inside a svelte application.
Run storybook via:
npm run storybookThis will start the storybook runtime and load a page in your browser that displays the storybook dashboard. This window will contain a list of components on the left hand side that there are stories for, as well as a story for each component (there can be multiple) that has been included in that comopnents story file.
See the ./src/stories/Counter.stories.ts file for an example of a stories file.
This stories file sets up a default meta object, and then below that contains separate blocks detailing different instances of the component we would like to display, each instance using or exercising the component in a slightly different manner.
Storybook for Custom Web Elements
Note: as the configuration currently stands, when you add a new component to test, you must import that component into the ./.storybook/preview.ts file, as done with the Counter component.
// .storybook/preview.ts import for each component tested
import '../src/lib/Counter.svelte';Executing a development server:
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --openEverything inside src/lib is part of your library, everything inside src/routes can be used as a showcase or preview app.
To test that you can build your library:
npm pack --dry-runExecute w/o the option to build a usable package.
To create a production version of your showcase app (note - update the version number inside package.json if installing or elsewhere or publishing):
npm run buildThe build script includes a cp command to copy a types file into the output dist folder, this is to be used by a consuming client as to alleviate any linting or type errors during client development.
To package the build output after executing npm run build:
npm packThis packaged file can be copied to another project and installed there directly using the npm install command, i.e. npm install poly-ui-0.0.1.tgz. This will register the poly-ui package at verison 0.0.1 as installed in your application.
To publish to npm after packaging the output:
npm publish --access=publicTo make poly-ui components available to the largest namespace possible, import the library in an originating file, i.e. an index or main.tsx file. For instance, you can import it in the top of a main.tsx file as:
import 'poly-ui';In our demo React application we also had to add a poly-ui.d.ts file in the src/ directory with the following content:
/// <reference types="poly-ui/types" />