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:
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);
}
}