Astro
This site is Astro, and every form on it is the live product.
---const form = import.meta.env.PUBLIC_FORM_ID;---
<formbuilder-form form={form}></formbuilder-form>
<script is:inline type="module" src="https://forms.justinjongstra.nl/formbuilder/asset/element.js"></script>Inside an island
Section titled “Inside an island”Because it is a custom element rather than a component, it works the same
inside any framework Astro renders. All three below are real islands on
this page, each with its own listener for fb:success.
<script setup lang="ts">import { onMounted, useTemplateRef } from 'vue';
defineProps<{ form: string }>();
const host = useTemplateRef<HTMLElement>('host');
onMounted(() => host.value?.addEventListener('fb:success', () => { // your analytics call here}));</script>
<template> <div ref="host"><formbuilder-form :form="form" /></div></template>Vue passes unknown elements straight through, so no isCustomElement
config, no wrapper package.
import { useEffect, useRef } from 'react';
export default function ContactForm({ form }: { form: string }) { const host = useRef<HTMLDivElement>(null);
useEffect(() => { const node = host.current; const onSuccess = () => {};
node?.addEventListener('fb:success', onSuccess);
return () => node?.removeEventListener('fb:success', onSuccess); }, []);
return ( <div ref={host}> {/* @ts-expect-error: a custom element React has no types for */} <formbuilder-form form={form} /> </div> );}React 19 handles custom elements properly. On 18 and below the tag still
renders and string attributes still work. What did not was setting
object properties or binding on* handlers for custom events, which is
why the listener goes on a ref. That version works on both.
<script lang="ts"> let { form }: { form: string } = $props();</script>
<div onfb:success={() => { /* your analytics call here */ }}> <formbuilder-form {form}></formbuilder-form></div>Svelte passes unknown elements through untouched, and fb:success
bubbles, so the listener can sit on the wrapper.
Starlight
Section titled “Starlight”This page is Starlight, so the same applies: put the tag in an .mdx file
or a component, add the script once with is:inline, and the form renders
inside the prose.