In Svelte, you give @usefillo/dom one element to own and destroy the renderer when the component leaves the page. That's the whole integration.
Install and mount
pnpm add @usefillo/dom<script lang="ts">
import { onMount } from "svelte";
import { renderForm } from "@usefillo/dom";
import "@usefillo/dom/styles.css";
let root: HTMLDivElement;
onMount(() => {
const form = renderForm(root, {
formId: "your-published-form-id",
onSubmitted: (responseId) => console.info("Fillo response", responseId),
});
return () => form.destroy();
});
</script>
<section aria-labelledby="feedback-title">
<h2 id="feedback-title">Product feedback</h2>
<div bind:this={root}></div>
</section>onMount only runs in the browser, so server rendering never touches the DOM. If the form ID is reactive, destroy the current renderer before mounting the next one into the same root.
Use a custom layout
For fully Svelte-owned markup, use createFormController from the same package: subscribe to state, call controller actions from your Svelte handlers, and destroy the controller on cleanup. If you replace the default renderer, keep labels, errors, focus movement, and pending state intact.
Test the interruptions
Try route changes during load and submit, validation focus, failed requests (answers should survive), upload cancellation, and clean teardown. Once a form is published, loading and submitting it needs no publishable key.
Try it
Start with a prompt and your coding agent builds the first form, staged for your review — or open the editor.
Related
- Contact example: Inspect the native states this component renders.
- Custom UI: Build around the framework-agnostic controller.
- Form is not submitting: Surface controller and network failures.
- Save and resume: Preserve progress across a later visit.