Embedding forms
Put a signup form on your own website with an embed code. An embedded form behaves exactly like the hosted page, confirmation email included.
Embed your form in a popup
Popup overlay opens the form over your page.
- Open Forms, select the form’s menu, then select Embed.
- Choose where the form is going and keep Popup overlay.
- Set the trigger and position, then select Get instructions.
- Copy the code and paste it where the steps say.
The code is a script tag, plus a link when the popup opens from one:
<a href="https://xoxo.email/your-slug" target="_blank" rel="noopener">Subscribe</a>
<script async src="https://xoxo.email/embed.js" data-form="your-slug"></script>
data-form is your form’s slug, the last part of its address at https://xoxo.email/your-slug. With nothing else set, any link on the page to that address opens the popup, so restyle the included link, or point a button you already have at the address and drop the link. The script can live anywhere on the page, and including it more than once is safe.
Trigger
Show it when someone… sets data-trigger-type. Click is the default and writes nothing into the code.
- Clicks a link to the form.
click, or nothing. Every link to the form’s address opens the popup. To open from something that isn’t a link as well, setdata-trigger-selectorto a CSS selector for it. - Is on the page for a few seconds.
delay. Opens afterdata-trigger-secondsseconds. - Scrolls down the page a bit.
scroll. Opens once the visitor has scrolleddata-trigger-percentof the page. - Is about to exit the site.
exit. Opens when the pointer leaves the top of the window.
Timed, scroll, and exit popups open once per page view. Edit the number in the code to change the delay or the depth:
<script
async
src="https://xoxo.email/embed.js"
data-form="your-slug"
data-trigger-type="delay"
data-trigger-seconds="8"
></script>
Position
Where it sits sets data-location. Center is the default and writes nothing into the code. The other positions are top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, and bottom-right.
<script
async
src="https://xoxo.email/embed.js"
data-form="your-slug"
data-trigger-type="exit"
data-location="bottom-right"
></script>
On a small screen the popup is centered, whatever the position.
Older browsers
The popup needs a browser from 2022 on. In older browsers the link opens the form’s own page in a new tab, and the timed, scroll, and exit triggers stay off so visitors never see a blocked popup. The link also works when the script can’t load.
Embed your form inline
In the page puts the form in the page flow. GoDaddy and Google Sites start here, because a popup would stay inside their fixed-height embed frame.
- Open Forms, select the form’s menu, then select Embed.
- Choose where the form is going, then choose In the page.
- Select Get instructions, copy the code, and paste it where the form should appear.
The code is an iframe plus the script:
<iframe
src="https://xoxo.email/your-slug"
title="Subscribe"
width="100%"
height="400"
loading="lazy"
style="border:0;display:block;color-scheme:normal"
></iframe>
<script async src="https://xoxo.email/embed.js"></script>
The iframe fills the available width, and the script resizes it to fit the form as it changes. Several forms can share one page and one script tag, and the script resizes any iframe that shows a XOXO form, including one you wrote yourself.
- Transparent background lets your site’s background show through. The form keeps its text colors and input styles. It adds
?transparent=1to the iframe’ssrc, so copy the code again after changing it. - Hide the referral badge on the embedded form by adding
?badge=0to the iframe’ssrc. Your form’s own page keeps whatever the form’s Referral badge switch says. - Starting height. The iframe’s
heightis its size until the script measures the form. Set it close to the real height to avoid a jump. - Lazy loading.
loading="lazy"holds off fetching a form below the fold until the reader scrolls near it. Remove it for a form at the top of the page.
If a site allows iframes but blocks scripts, the form still works at its set height, with scrolling. A builder whose embed block takes a URL rather than code can show the form’s own address the same way. If it blocks iframes too, link to the form’s own page instead.
Embed your form with JavaScript
The script also gives you a small API for popups, events, and styling. It works in browsers from 2016 on.
Open a popup from your own code
Load the script without data-form, then call window.xoxo.popup. This example omits async so the API is available on the next line:
<a id="subscribe" href="https://xoxo.email/your-slug" target="_blank" rel="noopener">Subscribe</a>
<script src="https://xoxo.email/embed.js"></script>
<script>
const form = window.xoxo.popup("your-slug", { location: "bottom-right" })
document.querySelector("#subscribe").addEventListener("click", (event) => {
event.preventDefault()
form.open()
})
</script>
All options are optional:
triggeris{ type: "click", selector },{ type: "delay", seconds },{ type: "scroll", percent }, or{ type: "exit" }. A click trigger opens from every link to the form, plus whateverselectormatches; the selector is optional. Without a trigger, the popup stays closed until you callopen().locationis one of the positions above.
The returned handle has open(), close(), and destroy(). Use destroy() to remove the popup and its listeners when leaving a view in a client-side app. In a browser without popup support, open() opens the form’s page in a new tab when called from a click, and does nothing otherwise.
Listen for events
Both styles dispatch xoxo:ready and xoxo:submit, and popups also dispatch xoxo:open and xoxo:close. Ready fires once, after the form has loaded, which for a popup is usually before it opens; the others fire each time. The events bubble up to the document. Their target is the inline iframe, or the xoxo-popup element for a popup. Register listeners before loading the script:
<script>
document.addEventListener("xoxo:ready", (event) => console.log("Form ready", event.target))
document.addEventListener("xoxo:submit", (event) => console.log("Form submitted", event.target))
</script>
<script async src="https://xoxo.email/embed.js"></script>
Events carry no personal data. xoxo:submit reports an accepted submission and can’t cancel it. It doesn’t mean the subscriber has confirmed their email.
Style the popup
The popup keeps its own styles in a shadow root, so your page’s CSS can’t change it by accident. Three parts are open to your stylesheet on purpose:
xoxo-popup::part(dialog)is the popup itself.xoxo-popup::part(frame)is the card holding the form.xoxo-popup::part(close)is the close button.
xoxo-popup::part(frame) {
border-radius: 0;
}
xoxo-popup::part(dialog) {
max-width: 420px;
}
The form inside is styled in the editor.