Developer Code Examples
Explore practical examples of integrating KirokuForms into your projects. From basic HTML to advanced API usage and custom styling, find the patterns you need.
Standard HTML Embed (Recommended)
The fastest way to integrate. It renders semantic HTML suitable for standard websites, blogs, and landing pages.
<script src="https://www.kirokuforms.com/embed.js"
data-kiroku-form-id="YOUR_FORM_ID"
async></script> React Component Embed
Renders your form dynamically on the client with a small bundled runtime (~12KB gzipped, Preact under the hood). Ideal for single-page apps (SPAs) that build their content in the browser.
<div id="form-root"></div>
<script src="https://www.kirokuforms.com/embed.js"
data-kiroku-form-id="YOUR_FORM_ID"
data-kiroku-target="#form-root"
data-kiroku-mode="react"
async></script> Multiple Forms on One Page
Embed as many forms as you want on a single page. Each form renders into its own container, keeps its own state, and submits to its own form ID, so they never interfere with each other. The embed script is fetched once (the browser caches it) and initializes every form exactly once.
One script tag per form
The simplest approach. Give each form its own target container so it renders exactly where you place it:
<div id="signup"></div>
<script src="https://www.kirokuforms.com/embed.js"
data-kiroku-form-id="FORM_A"
data-kiroku-target="#signup"
async></script>
<div id="contact"></div>
<script src="https://www.kirokuforms.com/embed.js"
data-kiroku-form-id="FORM_B"
data-kiroku-target="#contact"
async></script> Load once, initialize many
For single-page apps or pages with many forms, load the script once and
call KirokuEmbed.init() for each form. The script and its runtime
parse a single time, then each form renders into its own container:
<script src="https://www.kirokuforms.com/embed.js" async></script>
<div id="a"></div>
<div id="b"></div>
<script>KirokuEmbed.init({ formId: 'FORM_A', target: '#a' });
KirokuEmbed.init({ formId: 'FORM_B', target: '#b', mode: 'react' });
</script> Open a Popup on Demand
A form set to popup mode in its Display settings arms its own trigger (exit-intent or a delay). You can also open it from your own page: from a button, from your own JavaScript, or from a custom event. All three reuse the same modal, so focus trapping and reduced-motion handling come for free.
From a button: data-kiroku-open
Put data-kiroku-open="YOUR_FORM_ID" on any element. A click
opens that form in the popup. The handler is delegated from the document,
so buttons added after the script loads still work.
<script src="https://www.kirokuforms.com/embed.js" async></script>
<button data-kiroku-open="YOUR_FORM_ID">Join the newsletter</button>
From your code: window.KirokuForms.open()
Call window.KirokuForms.open(formId) whenever your own logic
decides the moment is right. An unknown form id fails quietly and leaves
your page untouched.
window.KirokuForms.open("YOUR_FORM_ID");
From an event: kiroku:open
Dispatch a document-level kiroku:open CustomEvent with the form
id in its detail. This keeps your trigger code fully
decoupled from the embed.
document.dispatchEvent(
new CustomEvent("kiroku:open", { detail: { formId: "YOUR_FORM_ID" } })
);
Per-placement trigger: data-kiroku-trigger
Override the form's saved popup trigger for a single placement with
data-kiroku-trigger on the script tag. Accepted values:
exit, delay:8000 (milliseconds),
inactivity:30000 (milliseconds of no interaction),
scroll:50 (percent of page height), click:#selector, visible:#selector (fires when the element scrolls into view),
and intent:hot (fires on a VeritaMetrics warm or hot engagement
signal). Combine several with commas; the first to fire wins. To require
both instead, join them with & (the composite
all trigger): intent:warm&exit opens only once
a warm visitor moves to leave.
<script src="https://www.kirokuforms.com/embed.js"
data-kiroku-form-id="YOUR_FORM_ID"
data-kiroku-trigger="scroll:50, click:#demo-cta"
async></script> Open a HITL Task in a Modal
A human-in-the-loop (HITL) task form is scoped to a task id and a token.
The page at /hitl/task/TASK_ID?token=TASK_TOKEN reads the token
from the URL and validates it before it renders the task. To show that task
in a modal on your own dashboard, point a same-origin iframe at the same
URL. The token stays in the query string, so the task submits through its
own page exactly as it does full screen.
<iframe
src="/hitl/task/TASK_ID?token=TASK_TOKEN"
title="HITL task"
style="width:100%;height:min(80vh,640px);border:none"
></iframe>
This iframe wrapper is the shipped path today. Our app drops that iframe
into the same accessible popup modal used above (the
openTaskModal helper), so focus trapping and reduced-motion
handling carry over. It is presentation only: it issues no fetch, adds no
auth header, and calls no API endpoint.
Future option: window.KirokuForms.openTask(taskId, token)
A token-aware window.KirokuForms.openTask(taskId, token) on
the embed is a possible future addition. It would be additive and would carry
the token in the URL, the same way the iframe does. It would not change
/api/submissions/task or /api/mcp/*: those
endpoints keep their current field names, structure, and
Bearer/body-token auth, which external clients depend on. This method
does not exist yet; use the iframe wrapper above.
Embed Customization
Our embed script is highly configurable. You can control rendering modes, target specific containers, and override styles to match your brand perfectly.
Looking for the full reference?
The most up-to-date list of configuration attributes, CSS variables, and advanced options is available directly in your dashboard.
Go to Dashboard → Select Form → Embed TabQuick Theming Example
Override our default CSS variables in your own stylesheet to instantly theme standard embeds:
/* Example: Customizing KirokuForms Embed with CSS Variables */
/* This applies if you are using a KirokuForms embed that respects these variables. */
/* Place this in your global CSS or a <style> tag on your page. */
/* :root or a specific wrapper for the KirokuForms embed */
.kiroku-form-custom-theme {
--kiroku-color-primary: #F97316; /* Human Orange */
--kiroku-color-text: #334155; /* Kiroku Slate */
--kiroku-color-border: #9ca3af; /* Gray-400 */
--kiroku-color-background: #F8FAFC; /* Kiroku White */
--kiroku-border-radius: 0.5rem; /* 8px */
--kiroku-font-family: 'Georgia', serif; /* Example custom font */
--kiroku-font-size: 1.1rem;
/* Button specific overrides */
--kiroku-button-text-color: white;
--kiroku-button-hover-bg-color: #fb923c; /* Lighter orange */
} HTML Form with Various Field Types
This example demonstrates an HTML form using different input types.
Remember to include JavaScript for submission to the /api/forms/YOUR_FORM_ID/submit endpoint with your API key, similar to the Quick Start guide.
<form id="allFieldsForm">
<div>
<label for="fullName">Full Name:</label>
<input type="text" id="fullName" name="fullName" required />
</div>
<div>
<label for="contactEmail">Email Address:</label>
<input type="email" id="contactEmail" name="contactEmail" required />
</div>
<div>
<label for="quantity">Quantity:</label>
<input type="number" id="quantity" name="quantity" min="1" max="100" />
</div>
<div>
<label for="comments">Comments:</label>
<textarea id="comments" name="comments" rows="5"></textarea>
</div>
<div>
<label for="serviceType">Service Type:</label>
<select id="serviceType" name="serviceType">
<option value="">--Please choose an option--</option>
<option value="support">Support</option>
<option value="sales">Sales</option>
<option value="feedback">Feedback</option>
</select>
</div>
<div>
<p>Preferred Contact Method:</p>
<input type="radio" id="contactEmailRadio" name="contactMethod" value="email" checked />
<label for="contactEmailRadio">Email</label><br/>
<input type="radio" id="contactPhoneRadio" name="contactMethod" value="phone" />
<label for="contactPhoneRadio">Phone</label>
</div>
<div>
<p>Interests:</p>
<input type="checkbox" id="interestTech" name="interests" value="technology" />
<label for="interestTech">Technology</label><br/>
<input type="checkbox" id="interestDesign" name="interests" value="design" />
<label for="interestDesign">Design</label>
</div>
<div>
<label for="appointmentDate">Appointment Date:</label>
<input type="date" id="appointmentDate" name="appointmentDate" />
</div>
<button type="submit">Submit Detailed Form</button>
</form>
<script>
// Basic JS submission logic (similar to quickstart) would go here,
// targeting "allFieldsForm" and posting to /api/forms/YOUR_FORM_ID/submit
// with an API Key.
</script> Note: For brevity, the JavaScript submission logic is omitted here but would be required as shown in the Quick Start Guide.
Styling: Complete Freestyle (Custom HTML & CSS)
When you integrate using your own HTML structure and submit via our API, you have 100% control over the styling. KirokuForms injects no CSS. Use your own stylesheets, utility classes (like Tailwind CSS), or any method you prefer.
HTML Structure:
<form id="freestyleForm" class="my-custom-form">
<div class="form-group">
<label for="customName" class="form-label">Your Name:</label>
<input type="text" id="customName" name="name" class="form-input" required />
</div>
<button type="submit" class="btn-submit-custom">Send It!</button>
</form> Custom CSS:
/* Your custom CSS - style it exactly how you want! */
.my-custom-form {
background-color: #f0f4f8;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.my-custom-form .form-group {
margin-bottom: 1.5rem;
}
.my-custom-form .form-label {
display: block;
color: #2c3e50;
margin-bottom: 0.5rem;
font-weight: bold;
}
.my-custom-form .form-input {
width: 100%;
padding: 0.75rem;
border: 2px solid #bdc3c7;
border-radius: 5px;
transition: border-color 0.3s;
}
.my-custom-form .form-input:focus {
border-color: #3498db; /* Kiroku Blue-like */
outline: none;
}
.my-custom-form .btn-submit-custom {
background-color: #2563EB; /* Kiroku Blue */
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
transition: background-color 0.3s;
}
.my-custom-form .btn-submit-custom:hover {
background-color: #1D4ED8; /* Darker Kiroku Blue */
} Remember to add JavaScript submission logic to post to `/api/forms/YOUR_FORM_ID/submit` with your API key.
Manual Fetch API Submission
This example expands on the Quick Start's JavaScript submission. It demonstrates a more structured approach to using the Fetch API for client-side submissions, including handling file uploads (if your form has them) and providing more detailed user feedback.
The code below is generated by our generateFetchExampleSet utility.
You would typically use this within your form's "Share" or "Embed" modal
in the KirokuForms dashboard.
HTML Structure:
<form id="kirokuCustomFetchForm-examplePage">
<h3>Example Fetch API Form</h3>
<div id="kirokuCustomFetchForm-examplePage-messages" style="display:none;"></div>
<div>
<label for="fetchName">Name:</label>
<input type="text" name="name" id="fetchName" required />
</div>
<div>
<label for="fetchEmail">Email:</label>
<input type="email" name="email" id="fetchEmail" required />
</div>
<button type="submit">Submit with Fetch</button>
</form> JavaScript Logic:
// JavaScript for Fetch API Example (generated by customIntegrationExamples.ts)
// Remember to replace YOUR_FORM_ID and YOUR_API_KEY
document.addEventListener('DOMContentLoaded', () => {
const formElement = document.getElementById('kirokuCustomFetchForm-examplePage');
const messagesDiv = document.getElementById('kirokuCustomFetchForm-examplePage-messages');
if (!formElement || !messagesDiv) {
console.error('Form or messages element not found');
return;
}
formElement.addEventListener('submit', async (event) => {
event.preventDefault();
// Show loading state
messagesDiv.style.display = 'block';
messagesDiv.innerHTML = '<p style="color: #2563EB;">Submitting...</p>';
try {
// Collect form data
const formData = new FormData(formElement);
const data = Object.fromEntries(formData.entries());
// Submit to KirokuForms API
const response = await fetch('/api/forms/YOUR_FORM_ID/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (response.ok) {
messagesDiv.innerHTML = '<p style="color: #10b981;">✓ Form submitted successfully!</p>';
formElement.reset();
} else {
messagesDiv.innerHTML = `<p style="color: #ef4444;">Error: ${result.error?.message || 'Submission failed'}</p>`;
}
} catch (error) {
console.error('Submission error:', error);
messagesDiv.innerHTML = '<p style="color: #ef4444;">Network error. Please try again.</p>';
}
});
console.log("Fetch example JS loaded for kirokuCustomFetchForm-examplePage.");
}); Manual React Integration
Integrate KirokuForms into your React applications. This example shows a basic React component for form handling and submission to our API.
This code is generated by our generateReactExampleCode utility,
often found in the form's "Share" or "Embed" modal.
// React Component Example (generated by customIntegrationExamples.ts)
// Remember to replace YOUR_FORM_ID and YOUR_API_KEY
import React, { useState } from 'react';
interface FormData {
name: string;
email: string;
message: string;
}
interface SubmissionStatus {
type: 'idle' | 'loading' | 'success' | 'error';
message?: string;
}
function KirokuFormReactExample() {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
message: ''
});
const [status, setStatus] = useState<SubmissionStatus>({ type: 'idle' });
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setStatus({ type: 'loading' });
try {
const response = await fetch('/api/forms/YOUR_FORM_ID/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json'
},
body: JSON.stringify(formData)
});
const result = await response.json();
if (response.ok) {
setStatus({
type: 'success',
message: 'Form submitted successfully!'
});
setFormData({ name: '', email: '', message: '' });
} else {
setStatus({
type: 'error',
message: result.error?.message || 'Submission failed'
});
}
} catch (error) {
setStatus({
type: 'error',
message: 'Network error. Please try again.'
});
}
};
return (
<div className="max-w-md mx-auto">
<form onSubmit={handleSubmit} className="space-y-4">
<h3 className="text-lg font-semibold">React Form Example</h3>
<div>
<label htmlFor="name" className="block text-sm font-medium">
Name:
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleInputChange}
required
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium">
Email:
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleInputChange}
required
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium">
Message:
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleInputChange}
rows={4}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
/>
</div>
<button
type="submit"
disabled={status.type === 'loading'}
className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:opacity-50"
>
{status.type === 'loading' ? 'Submitting...' : 'Submit React Form'}
</button>
{status.message && (
<div className={`p-3 rounded-md ${
status.type === 'success'
? 'bg-green-50 text-green-800'
: 'bg-red-50 text-red-800'
}`}>
{status.message}
</div>
)}
</form>
</div>
);
}
export default KirokuFormReactExample; Server-Side Submission (Node.js Example)
For maximum security (protecting your API Key) and for backend workflows, submit data to KirokuForms from your server. Here's a conceptual example using Node.js and Express.
// Example: Server-Side Submission with Node.js and Express
// 1. Frontend HTML (posts to your backend)
// <form action="/your-backend-submit-route" method="POST">
// <input type="email" name="email" />
// <button type="submit">Submit via Backend</button>
// </form>
// 2. Backend Express Route (e.g., server.js)
const express = require('express');
const fetch = require('node-fetch'); // or another HTTP client
const app = express();
app.use(express.urlencoded({ extended: true })); // To parse form data
const KIROKU_FORM_ID = 'YOUR_FORM_ID';
const KIROKU_API_KEY = 'YOUR_SECRET_API_KEY'; // Keep this secret on the server!
app.post('/your-backend-submit-route', async (req, res) => {
const submissionData = req.body; // Contains { email: '...' }
try {
const kirokuResponse = await fetch(`https://www.kirokuforms.com/api/forms/${KIROKU_FORM_ID}/submit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${KIROKU_API_KEY}`,
'Accept': 'application/json'
},
body: JSON.stringify(submissionData)
});
const result = await kirokuResponse.json();
if (kirokuResponse.ok) {
// Handle success (e.g., redirect user, show success message)
res.status(200).send(`Successfully submitted to KirokuForms: ${JSON.stringify(result)}`);
} else {
// Handle error from KirokuForms
console.error('KirokuForms API Error:', result);
res.status(kirokuResponse.status).send(`Error submitting to KirokuForms: ${result.error?.message || 'Unknown error'}`);
}
} catch (error) {
console.error('Error in backend submission:', error);
res.status(500).send('Internal server error.');
}
});
// app.listen(3000, () => console.log('Your backend server running on port 3000')); Working with File Uploads
KirokuForms supports file uploads. When your form includes a field of type 'file', your JavaScript submission logic needs to use FormData to correctly send the file(s). Our Fetch API and React examples (generated by generateFetchExampleSet and generateReactExampleCode respectively) automatically detect file input fields and use FormData. Refer to those examples when implementing file uploads. Important: When using FormData for file uploads, do not manually set the Content-Type header in your fetch request. The browser will set it correctly to multipart/form-data along with the necessary boundary.
FormData for file uploads, do not manually set the
Content-Type header in your fetch request. The
browser will set it correctly to multipart/form-data along with
the necessary boundary.
Ready to Build?
Dive deeper into our documentation or start integrating KirokuForms today.