A
Atlas
...

JavaScript Integration

Use JavaScript for more control over form submission, validation, and user feedback.

Testing Locally

To test from localhost, register your IP in form settings:

  • Keep your form in Sandbox Mode (default)
  • Go to Form Settings → Localhost Testing
  • Click Register My IP
  • Optional: For extra security, generate a Sandbox API Key and include it in requests:

    javascript
    // Add .env file (not committed to git)
    const ATLAS_KEY = 'sk_sandbox_xyz123...';
    
    const response = await fetch('https://atlasforms.app/f/YOUR_FORM_ID', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Atlas-Key': ATLAS_KEY,  // Optional extra security
      },
      body: JSON.stringify(data),
    });

    Note: When you go Live, localhost will be blocked. Use a production domain.

    Basic Fetch

    javascript
    const form = document.querySelector('form');
    
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
    
      const formData = new FormData(form);
      const data = Object.fromEntries(formData);
    
      try {
        const response = await fetch('https://atlasforms.app/f/YOUR_FORM_ID', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        });
    
        const result = await response.json();
    
        if (response.ok) {
          console.log('Success:', result.submission_id);
          form.reset();
          alert('Thank you for your submission!');
        } else {
          console.error('Error:', result.error);
          alert(result.error || 'Something went wrong');
        }
      } catch (error) {
        console.error('Network error:', error);
        alert('Failed to submit. Please try again.');
      }
    });

    With Loading State

    javascript
    const form = document.querySelector('form');
    const submitBtn = form.querySelector('button[type="submit"]');
    
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
    
      // Disable button and show loading
      submitBtn.disabled = true;
      submitBtn.textContent = 'Sending...';
    
      try {
        const formData = new FormData(form);
    
        const response = await fetch('https://atlasforms.app/f/YOUR_FORM_ID', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(Object.fromEntries(formData)),
        });
    
        const result = await response.json();
    
        if (response.ok) {
          // Success
          form.reset();
          showMessage('success', 'Message sent successfully!');
        } else {
          // Server error
          showMessage('error', result.error || 'Failed to send message');
        }
      } catch (error) {
        // Network error
        showMessage('error', 'Network error. Please try again.');
      } finally {
        // Re-enable button
        submitBtn.disabled = false;
        submitBtn.textContent = 'Send';
      }
    });
    
    function showMessage(type, text) {
      const msg = document.createElement('div');
      msg.className = `message ${type}`;
      msg.textContent = text;
      form.appendChild(msg);
      setTimeout(() => msg.remove(), 5000);
    }

    With File Uploads

    Don't set Content-Type when sending files - let the browser handle it:

    javascript
    const form = document.querySelector('form');
    
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
    
      const formData = new FormData(form);
    
      // FormData automatically handles files
      const response = await fetch('https://atlasforms.app/f/YOUR_FORM_ID', {
        method: 'POST',
        body: formData, // Don't set Content-Type header!
      });
    
      const result = await response.json();
    
      if (response.ok) {
        console.log('Files uploaded:', result.files);
      }
    });

    Upload Progress

    Track upload progress for large files:

    javascript
    const form = document.querySelector('form');
    const progressBar = document.querySelector('.progress-bar');
    
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
    
      const formData = new FormData(form);
    
      const xhr = new XMLHttpRequest();
    
      xhr.upload.addEventListener('progress', (e) => {
        if (e.lengthComputable) {
          const percent = Math.round((e.loaded / e.total) * 100);
          progressBar.style.width = `${percent}%`;
          progressBar.textContent = `${percent}%`;
        }
      });
    
      xhr.addEventListener('load', () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          const result = JSON.parse(xhr.responseText);
          console.log('Success:', result);
        } else {
          console.error('Error:', xhr.responseText);
        }
      });
    
      xhr.addEventListener('error', () => {
        console.error('Network error');
      });
    
      xhr.open('POST', 'https://atlasforms.app/f/YOUR_FORM_ID');
      xhr.send(formData);
    });

    Client-Side Validation

    Validate before submitting:

    javascript
    const form = document.querySelector('form');
    
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
    
      // Client-side validation
      const email = form.querySelector('[name="email"]').value;
      const phone = form.querySelector('[name="phone"]').value;
    
      if (!isValidEmail(email)) {
        alert('Please enter a valid email address');
        return;
      }
    
      if (phone && !isValidPhone(phone)) {
        alert('Please enter a valid phone number');
        return;
      }
    
      // Submit if valid
      const formData = new FormData(form);
      // ... submit code
    });
    
    function isValidEmail(email) {
      return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    }
    
    function isValidPhone(phone) {
      return /^[\d\s\-\+\(\)]{10,}$/.test(phone);
    }

    Handling Errors

    javascript
    async function submitForm(form) {
      const response = await fetch('https://atlasforms.app/f/YOUR_FORM_ID', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(Object.fromEntries(new FormData(form))),
      });
    
      const result = await response.json();
    
      switch (response.status) {
        case 200:
        case 201:
          return { success: true, data: result };
    
        case 400:
          // Validation error
          return { success: false, error: result.error, details: result.details };
    
        case 403:
          // Origin not allowed or form inactive
          return { success: false, error: 'Form is not accepting submissions' };
    
        case 429:
          // Rate limited
          return {
            success: false,
            error: `Too many requests. Try again in ${result.retry_after} seconds`,
          };
    
        default:
          return { success: false, error: 'An unexpected error occurred' };
      }
    }

    TypeScript

    typescript
    interface SubmissionResponse {
      success: true;
      submission_id: string;
      files?: Array<{
        id: string;
        filename: string;
        type: string;
        size: number;
      }>;
    }
    
    interface SubmissionError {
      error: string;
      details?: Array<{
        field: string;
        error: string;
      }>;
    }
    
    async function submitToAtlas(
      formId: string,
      data: Record<string, unknown>
    ): Promise<SubmissionResponse> {
      const response = await fetch(`https://atlasforms.app/f/${formId}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
    
      if (!response.ok) {
        const error: SubmissionError = await response.json();
        throw new Error(error.error);
      }
    
      return response.json();
    }
    
    // Usage
    try {
      const result = await submitToAtlas('YOUR_FORM_ID', {
        name: 'John Doe',
        email: 'john@example.com',
      });
      console.log('Submitted:', result.submission_id);
    } catch (error) {
      console.error('Failed:', error.message);
    }

    Module Pattern

    Create a reusable Atlas client:

    javascript
    // atlas.js
    const atlas = {
      formId: null,
    
      init(formId) {
        this.formId = formId;
        return this;
      },
    
      async submit(data, options = {}) {
        const url = `https://atlasforms.app/f/${this.formId}`;
    
        const fetchOptions = {
          method: 'POST',
        };
    
        if (data instanceof FormData) {
          fetchOptions.body = data;
        } else {
          fetchOptions.headers = { 'Content-Type': 'application/json' };
          fetchOptions.body = JSON.stringify(data);
        }
    
        const response = await fetch(url, fetchOptions);
        const result = await response.json();
    
        if (!response.ok) {
          throw new AtlasError(result.error, response.status, result);
        }
    
        return result;
      },
    };
    
    class AtlasError extends Error {
      constructor(message, status, data) {
        super(message);
        this.status = status;
        this.data = data;
      }
    }
    
    export default atlas;
    
    // Usage
    import atlas from './atlas.js';
    
    atlas.init('YOUR_FORM_ID');
    
    try {
      const result = await atlas.submit({ name: 'John', email: 'john@example.com' });
      console.log(result);
    } catch (error) {
      if (error instanceof AtlasError) {
        console.log('Status:', error.status);
        console.log('Details:', error.data);
      }
    }