Form Embedding

Embed forms on your website using JavaScript widgets, iframes, or standalone pages.

Overview

ArcanFlows forms can be embedded in your website or application using multiple methods. Choose the approach that best fits your technical requirements and use case.

Embedding Methods

MethodUse CaseCustomizationSetup
JavaScript WidgetMost flexible, full styling controlHighMedium
IframeSimple, isolated stylingMediumEasy
Standalone PageQuick sharing, no codeLowNone
React ComponentReact applicationsHighMedium

JavaScript Widget

Basic Installation

Add the script to your HTML:

html
<script src="https://cdn.arcanflows.com/forms.js"></script>

Render Form

html
<div id="my-form"></div>

<script>
  ArcanFlows.form({
    formId: 'form_abc123',
    container: '#my-form'
  });
</script>

With Options

html
<script>
  ArcanFlows.form({
    formId: 'form_abc123',
    container: '#my-form',
    theme: 'light',
    prefill: {
      email: 'user@example.com',
      name: 'John Doe'
    },
    onSubmit: function(data) {
      console.log('Form submitted:', data);
    },
    onError: function(error) {
      console.error('Form error:', error);
    }
  });
</script>

Full Configuration

javascript
ArcanFlows.form({
  // Required
  formId: 'form_abc123',
  container: '#my-form',

  // Theme
  theme: 'light', // 'light', 'dark', 'auto', 'custom'
  customTheme: {
    primaryColor: '#6366F1',
    backgroundColor: '#FFFFFF',
    textColor: '#1F2937',
    borderRadius: '8px',
    fontFamily: 'Inter, sans-serif'
  },

  // Behavior
  showBranding: false,
  submitButtonText: 'Send Message',
  successMessage: 'Thank you for your submission!',
  redirectUrl: '/thank-you',
  resetOnSubmit: true,

  // Prefill
  prefill: {
    field1: 'value1',
    field2: 'value2'
  },

  // Hidden fields
  hiddenFields: {
    source: 'website',
    campaign: 'summer2025',
    referrer: document.referrer
  },

  // Validation
  validateOnBlur: true,
  validateOnChange: false,
  showInlineErrors: true,

  // Callbacks
  onLoad: function() {
    console.log('Form loaded');
  },
  onSubmit: function(data) {
    console.log('Submitted:', data);
    // Return false to prevent default success behavior
  },
  onSuccess: function(response) {
    console.log('Success:', response);
  },
  onError: function(error) {
    console.error('Error:', error);
  },
  onFieldChange: function(field, value) {
    console.log('Field changed:', field, value);
  },
  onPageChange: function(from, to) {
    console.log('Page changed:', from, '->', to);
  }
});

Multiple Forms

html
<div id="contact-form"></div>
<div id="newsletter-form"></div>

<script>
  // Contact form
  const contactForm = ArcanFlows.form({
    formId: 'form_contact',
    container: '#contact-form'
  });

  // Newsletter form
  const newsletterForm = ArcanFlows.form({
    formId: 'form_newsletter',
    container: '#newsletter-form'
  });
</script>

Programmatic Control

javascript
const form = ArcanFlows.form({
  formId: 'form_abc123',
  container: '#my-form'
});

// Methods
form.reset();                    // Reset form
form.submit();                   // Programmatic submit
form.validate();                 // Validate all fields
form.setValue('email', 'new@example.com');
form.getValue('email');          // Get field value
form.getValues();                // Get all values
form.setPage(2);                 // Go to page (multi-step)
form.disable();                  // Disable form
form.enable();                   // Enable form
form.destroy();                  // Remove form

// Events
form.on('submit', function(data) { });
form.on('error', function(error) { });
form.on('field:change', function(field, value) { });
form.off('submit');              // Remove listener

Iframe Embed

Basic Iframe

html
<iframe
  src="https://forms.arcanflows.com/f/form_abc123"
  width="100%"
  height="600"
  frameborder="0"
></iframe>

With Parameters

html
<iframe
  src="https://forms.arcanflows.com/f/form_abc123?theme=dark&prefill_email=user@example.com"
  width="100%"
  height="600"
  frameborder="0"
  allow="clipboard-write"
></iframe>

URL Parameters

ParameterDescriptionExample
themeColor theme?theme=dark
prefill_*Prefill fields?prefill_email=x@y.com
hide_*Hide fields?hide_company=true
brandingShow branding?branding=false
redirectSuccess redirect?redirect=/thanks
embedEmbed mode?embed=true

Responsive Iframe

html
<style>
  .form-container {
    position: relative;
    width: 100%;
    padding-bottom: 75%; /* Aspect ratio */
    height: 0;
    overflow: hidden;
  }
  .form-container iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: none;
  }
</style>

<div class="form-container">
  <iframe src="https://forms.arcanflows.com/f/form_abc123?embed=true"></iframe>
</div>

Auto-Resize Iframe

html
<iframe
  id="arcanflows-form"
  src="https://forms.arcanflows.com/f/form_abc123?embed=true"
  width="100%"
  height="400"
  frameborder="0"
></iframe>

<script>
  window.addEventListener('message', function(e) {
    if (e.data.type === 'arcanflows:resize') {
      document.getElementById('arcanflows-form').height = e.data.height;
    }
  });
</script>

Cross-Origin Communication

javascript
window.addEventListener('message', function(e) {
  // Verify origin
  if (e.origin !== 'https://forms.arcanflows.com') return;

  switch (e.data.type) {
    case 'arcanflows:loaded':
      console.log('Form loaded');
      break;
    case 'arcanflows:submit':
      console.log('Form submitted:', e.data.submission);
      break;
    case 'arcanflows:resize':
      // Handle resize
      break;
    case 'arcanflows:error':
      console.error('Form error:', e.data.error);
      break;
  }
});

Standalone Page

Share your form with a direct link:

https://forms.arcanflows.com/f/form_abc123

Custom Domain

Configure your own domain:

https://forms.yourcompany.com/contact

QR Code

Generate a QR code for your form URL to use in print materials, signage, or events.

https://forms.arcanflows.com/f/form_abc123?
  theme=dark&
  prefill_name=John&
  prefill_email=john@example.com&
  utm_source=campaign

React Component

Installation

bash
npm install @arcanflows/react-forms

Basic Usage

jsx
import { Form } from '@arcanflows/react-forms';

function ContactPage() {
  return (
    <Form
      formId="form_abc123"
      onSubmit={(data) => console.log(data)}
    />
  );
}

With Props

jsx
import { Form } from '@arcanflows/react-forms';

function ContactPage() {
  const handleSubmit = async (data) => {
    // Custom submit handling
    await myApi.createContact(data);
  };

  return (
    <Form
      formId="form_abc123"
      theme="dark"
      prefill={{
        email: user?.email,
        name: user?.name
      }}
      hiddenFields={{
        userId: user?.id
      }}
      onSubmit={handleSubmit}
      onError={(error) => toast.error(error.message)}
      className="my-form"
      showBranding={false}
    />
  );
}

Controlled Mode

jsx
import { Form, useForm } from '@arcanflows/react-forms';

function ContactPage() {
  const form = useForm('form_abc123');

  return (
    <div>
      <Form form={form} />
      <button onClick={() => form.reset()}>Reset</button>
      <button onClick={() => form.submit()}>Submit</button>
    </div>
  );
}

TypeScript

typescript
import { Form, FormSubmission } from '@arcanflows/react-forms';

interface ContactFormData {
  name: string;
  email: string;
  message: string;
}

function ContactPage() {
  const handleSubmit = (data: FormSubmission<ContactFormData>) => {
    console.log(data.values.email);
  };

  return (
    <Form<ContactFormData>
      formId="form_abc123"
      onSubmit={handleSubmit}
    />
  );
}

JavaScript Popup

javascript
ArcanFlows.popup({
  formId: 'form_abc123',
  trigger: 'button#contact-btn',
  size: 'medium', // 'small', 'medium', 'large', 'fullscreen'
  animation: 'fade', // 'fade', 'slide', 'scale'
  closeOnOverlayClick: true,
  closeOnEscape: true
});

Trigger Types

javascript
// Button click
ArcanFlows.popup({
  formId: 'form_abc123',
  trigger: {
    type: 'click',
    selector: '.open-form'
  }
});

// Time delay
ArcanFlows.popup({
  formId: 'form_abc123',
  trigger: {
    type: 'delay',
    delay: 5000 // 5 seconds
  }
});

// Scroll percentage
ArcanFlows.popup({
  formId: 'form_abc123',
  trigger: {
    type: 'scroll',
    percentage: 50
  }
});

// Exit intent
ArcanFlows.popup({
  formId: 'form_abc123',
  trigger: {
    type: 'exit'
  }
});

// Programmatic
const popup = ArcanFlows.popup({
  formId: 'form_abc123',
  trigger: {
    type: 'manual'
  }
});
popup.open();
popup.close();
javascript
ArcanFlows.popup({
  formId: 'form_abc123',
  style: {
    overlay: {
      backgroundColor: 'rgba(0, 0, 0, 0.7)'
    },
    modal: {
      maxWidth: '600px',
      borderRadius: '16px',
      padding: '32px'
    }
  }
});

Slider/Slide-in Forms

javascript
ArcanFlows.slider({
  formId: 'form_abc123',
  position: 'right', // 'left', 'right', 'bottom'
  width: '400px',
  trigger: 'button#help-btn'
});

Inline Embed Options

Replace Element

html
<div
  data-arcanflows-form="form_abc123"
  data-theme="light"
  data-prefill-email="user@example.com"
></div>

<script src="https://cdn.arcanflows.com/forms.js" async></script>

Auto-Discovery

javascript
// Initialize all forms on page
ArcanFlows.initAll();

Styling Embedded Forms

CSS Override

css
/* Target embedded form */
.arcanflows-form {
  --af-primary: #6366F1;
  --af-background: #F9FAFB;
  --af-text: #1F2937;
  --af-border: #E5E7EB;
  --af-error: #EF4444;
  --af-success: #10B981;
  --af-radius: 8px;
  --af-font: 'Inter', sans-serif;
}

/* Specific elements */
.arcanflows-form .af-input {
  border-width: 2px;
}

.arcanflows-form .af-button-submit {
  text-transform: uppercase;
  font-weight: 600;
}

Shadow DOM Styling

javascript
ArcanFlows.form({
  formId: 'form_abc123',
  container: '#my-form',
  useShadowDom: false, // Disable for full CSS access
  injectStyles: true
});

Security

Content Security Policy

Add ArcanFlows to your CSP:

Content-Security-Policy:
  script-src 'self' https://cdn.arcanflows.com;
  frame-src 'self' https://forms.arcanflows.com;
  connect-src 'self' https://api.arcanflows.com;

Domain Restrictions

Configure allowed embedding domains in your form settings to prevent unauthorized embedding.

Performance

Lazy Loading

javascript
// Load form when visible
ArcanFlows.form({
  formId: 'form_abc123',
  container: '#my-form',
  lazyLoad: true,
  lazyLoadThreshold: 200 // pixels before viewport
});

Async Loading

html
<script src="https://cdn.arcanflows.com/forms.js" async defer></script>

<script>
  window.ArcanFlowsReady = window.ArcanFlowsReady || [];
  window.ArcanFlowsReady.push(function() {
    ArcanFlows.form({
      formId: 'form_abc123',
      container: '#my-form'
    });
  });
</script>

Analytics & Tracking

Built-in Analytics

javascript
ArcanFlows.form({
  formId: 'form_abc123',
  container: '#my-form',
  analytics: {
    enabled: true,
    trackViews: true,
    trackInteractions: true,
    trackSubmissions: true,
    trackAbandonment: true
  }
});

Custom Tracking

javascript
ArcanFlows.form({
  formId: 'form_abc123',
  container: '#my-form',
  onLoad: function() {
    gtag('event', 'form_view', { form_id: 'contact' });
  },
  onSubmit: function(data) {
    gtag('event', 'form_submit', { form_id: 'contact' });
  },
  onError: function(error) {
    gtag('event', 'form_error', { form_id: 'contact', error: error.message });
  }
});

Troubleshooting

Common Issues

Form not loading:

  • Check formId is correct
  • Verify script is loaded
  • Check browser console for errors
  • Ensure container element exists

Styling issues:

  • Check CSS specificity
  • Disable Shadow DOM if needed
  • Use CSS custom properties

Submission errors:

  • Check network requests
  • Verify API connectivity
  • Check form configuration

Debug Mode

javascript
ArcanFlows.form({
  formId: 'form_abc123',
  container: '#my-form',
  debug: true // Enables console logging
});

Best Practices

  1. Use async loading - Don't block page render
  2. Lazy load below fold - Improve initial load
  3. Match site styling - Consistent UX
  4. Test responsively - Works on all devices
  5. Handle errors - Graceful fallbacks
  6. Track analytics - Monitor performance
  7. Secure embedding - Restrict domains
  8. Prefill when possible - Reduce friction