Web apps

Embed on your website

Render your form inline on any web page with two small options: the script loader or a plain iframe. Both support every major framework. For code-level integration, the eesyform-embed npm package ships typed React, Vue and vanilla bindings.

1Enable embedding

In the builder, open Share & embed and turn on Allow embedding. The embed URL only serves published forms, so make sure your form is published first.

2The script loader

The loader finds every data-ff-embed container on the page and mounts an auto-resizing iframe inside it. Include the script tag exactly once per page, even if you have several forms.

index.html
<!doctype html>
<html>
  <head>
    <title>Contact</title>
  </head>
  <body>
    <h1>Get in touch</h1>

    <!-- 1. The container EesyForm fills in -->
    <div data-ff-embed data-ff-form="my-form-abc123"></div>

    <!-- 2. The loader (one tag per page) -->
    <script async src="https://YOUR-EESYFORM-HOST.com/embed.js"></script>
  </body>
</html>

Options & events

Configure each embed with data attributes on the container:

  • data-ff-host — override the EesyForm host (auto-detected from the script tag by default)
  • data-ff-height — initial height in pixels before the form measures itself
  • data-ff-mode inline (default), popup, slider, side-tab or full-page
  • data-ff-trigger — label for the launch button used by non-inline modes
  • data-ff-width — panel width in pixels for slider and side-tab modes (default 380)
  • data-ff-position right, left or bottom edge for the slider and side-tab modes
Options
<!-- Optional data attributes -->
<div
  data-ff-embed
  data-ff-form="my-form-abc123"

  <!-- Force a different EesyForm host -->
  data-ff-host="https://forms.mycompany.com"

  <!-- Initial height before the form measures itself -->
  data-ff-height="480"

  <!-- Launch style: inline (default), popup, slider, side-tab, full-page -->
  data-ff-mode="slider"

  <!-- Trigger button label for non-inline modes -->
  data-ff-trigger="Open form"

  <!-- Edge for slider / side-tab: right (default), left, bottom -->
  data-ff-position="right"
></div>

<script async src="https://YOUR-EESYFORM-HOST.com/embed.js"></script>
Listening for submissions
<!-- Listen for a completed submission (detail is { type: "ff:submit" }) -->
<script>
  document.addEventListener("ffSubmit", (event) => {
    console.log("Form completed!", event.detail);
  });
</script>

<!-- ...or the global callback (called with the container element) -->
<script>
  window.ffSubmit = function (container, detail) {
    console.log("Completed in", container, detail);
  };
</script>

3Embed modes

Beyond inline, the script loader supports four launch styles. Pick a mode with data-ff-mode — the loader builds the trigger button and panel for you.

  • Popup — a button opens the form in a centered modal with an overlay.
  • Slider — a button slides a panel in from the right, left or bottom edge.
  • Side tab — a slim tab pinned to the page edge opens a panel when clicked.
  • Full page — the form covers the entire viewport.
Popup
<div data-ff-embed data-ff-form="my-form-abc123"
     data-ff-mode="popup"
     data-ff-trigger="Open feedback form"></div>
<script async src="https://YOUR-EESYFORM-HOST.com/embed.js"></script>
Side tab on the left edge
<div data-ff-embed data-ff-form="my-form-abc123"
     data-ff-mode="side-tab"
     data-ff-position="left"
     data-ff-trigger="Leave feedback"></div>
<script async src="https://YOUR-EESYFORM-HOST.com/embed.js"></script>

4Sharing & social preview

Every published form has a shareable link at https://YOUR-EESYFORM-HOST.com/r/<slug>. In the builder's Share & embed dialog you can copy the link, download a QR code for print materials, and share directly to X, Facebook, LinkedIn, WhatsApp or email.

When the link is shared, social platforms render anOpen Graph preview card with the form's title and description. The preview image is the default EesyForm card (the image is static; per-form themed images are not generated). If you use a custom domain, the preview URL reflects it, but the image stays the default.

5The iframe embed

No script? Just drop the iframe anywhere. The embed page resizes itself and reports its height back, but a fixed height is used until the first measurement arrives.

iframe embed
<iframe
  src="https://YOUR-EESYFORM-HOST.com/r/my-form-abc123/embed"
  width="100%"
  height="640"
  frameborder="0"
  style="border: 0; display: block; max-width: 100%"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; payment"
  loading="lazy"
></iframe>

6Framework recipes

For app code, install the package and use its bindings — no manual script injection needed.

Terminal
npm install eesyform-embed

Vanilla JS

Mount a form imperatively with embedForm, or keep the declarative data-ff-embed markup and scan it with mountAll.

embed.js
import { embedForm } from "eesyform-embed";

const handle = embedForm(document.getElementById("form"), {
  form: "my-form-abc123",
  host: "https://forms.example.com",
  height: 480,
  mode: "popup",            // inline | popup | slider | side-tab | full-page
  trigger: "Open form",     // label for non-inline modes
  position: "right",        // right | left | bottom (slider / side-tab)
  onSubmit: (detail) => console.log("Completed", detail),
});

// later
handle.unmount();
Declarative
import { mountAll } from "eesyform-embed";
mountAll();

React (18 / 19)

ContactPage.tsx
import { EesyForm } from "eesyform-embed/react";

export default function ContactPage() {
  return (
    <EesyForm
      form="my-form-abc123"
      host="https://forms.example.com"
      onSubmit={(detail) => console.log("Completed", detail)}
    />
  );
}
Hook variant
import { useEesyForm } from "eesyform-embed/react";

function ContactPage() {
  const { ref, submit } = useEesyForm({ form: "my-form-abc123" });
  return <div ref={ref} />;
}

Angular

EesyForm ships the framework-agnostic core; Angular directives are compiled by your own app, so add a tiny standalone directive that calls embedForm.

eesy-form.directive.ts
import { Directive, ElementRef, Input, OnDestroy, OnInit } from "@angular/core";
import { embedForm, type EmbedHandle } from "eesyform-embed";

@Directive({
  selector: "[ffForm]",
  standalone: true,
})
export class EesyFormDirective implements OnInit, OnDestroy {
  @Input("ffForm") form = "";
  @Input() ffHost?: string;
  @Input() ffHeight?: number;
  private handle?: EmbedHandle;

  constructor(private el: ElementRef<HTMLElement>) {}

  ngOnInit() {
    this.handle = embedForm(this.el.nativeElement, {
      form: this.form,
      host: this.ffHost,
      height: this.ffHeight,
    });
  }

  ngOnDestroy() {
    this.handle?.unmount();
  }
}
Usage
<div ffForm="my-form-abc123" ffHost="https://forms.example.com"></div>

Vue 3

ContactPage.vue
<script setup>
import { EesyForm } from "eesyform-embed/vue";
</script>

<template>
  <EesyForm form="my-form-abc123" host="https://forms.example.com" />
</template>

Next.js (App Router)

The React binding is a client component, so it works directly in App Router pages — including server components — with no extra setup.

app/contact/page.tsx
import { EesyForm } from "eesyform-embed/react";

export default function ContactPage() {
  return (
    <main>
      <h1>Contact us</h1>
      <EesyForm form="my-form-abc123" host="https://forms.example.com" />
    </main>
  );
}
Note on cross-site embedding — the embed page uses the form's own theme, so it inherits your brand colors, logo and font automatically. Password-protected and closed forms show their existing gate screens inside the iframe. The embedded form also displays a small "Powered by EesyForm" footer; on the Pro plan you can remove it from the form's branding settings. To build a fully custom UI instead, see the headless API.