DraftKit transforms any HTML form into an AI-powered content generator with just a few data attributes. No complex setup, no API integration headaches - just add our script and watch your forms come alive with intelligent content generation.
Imagine your users filling out a product form. They enter a product name and category, then click "Generate Description" - and boom! A compelling, context-aware product description appears instantly. That's DraftKit.
<\!-- This is all it takes -->
<script src="https://app.draftkit.io/draftkit.js" data-api-key="YOUR_KEY"></script>
<form>
<input name="product_name" data-draftkit-context>
<select name="category" data-draftkit-context>
<option>Electronics</option>
<option>Fashion</option>
</select>
<textarea name="description"
data-draftkit-prompt="prompt_product_desc_v2"></textarea>
<\!-- ✨ A "Generate Draft" button appears automatically\! -->
</form>
For Your Users:
- Beat writer's block with AI-powered suggestions
- Generate professional content in seconds
- Maintain consistency across all content
- Save hours on repetitive writing tasks
For Developers:
- Zero dependencies - pure vanilla JavaScript
- Works with any framework (React, Vue, vanilla HTML)
- Simple data attributes API
- Automatic UI generation
- Full event system for customization
- Respects your existing form structure
- Smart Context Collection - Automatically gathers relevant form data to generate contextual content
- Flexible Integration - Use auto-generated buttons or create your own custom UI
- Event-Driven - Hook into the generation lifecycle with standard DOM events
- Privacy-First - Explicitly exclude sensitive fields from context collection
- Framework Agnostic - Works everywhere: static sites, SPAs, server-rendered apps
Develop a standalone, embeddable JavaScript library that can be included in any website to add AI-powered content generation capabilities to HTML forms. The library will identify form fields with specific data attributes, add "Generate Draft" buttons, collect context from specified fields, send it to our backend API, process it with an LLM, and insert the generated content back into the form field.
- Create a simple JavaScript library served via Rails route (no build tools/bundling)
- Library will be available at
/draftkit.js
route in Rails application - Support modern browsers (Chrome, Firefox, Safari, Edge)
- No external dependencies (vanilla JavaScript only)
- Support both synchronous and asynchronous loading patterns
- CORS support for cross-domain API requests
- Lightweight implementation (<50KB uncompressed)
- Detect form fields with
data-draftkit-prompt
attribute - Identify context fields with
data-draftkit-context
attribute - Automatically create and insert "Generate Draft" buttons next to target fields
- Support custom button implementation via
data-draftkit-button
attribute - Collect context from marked fields (using field's name attribute by default)
- Handle button click events and loading states
- Make API requests to DraftKit backend (mock endpoints for this PR)
- Insert generated content into target fields
- Support rich text editors (if present)
- Add thumbs up/down rating UI after content generation
- Handle and display errors gracefully
- Fire custom events for developer hooks
data-draftkit-context
: Mark fields to include in context (uses field'sname
attribute as key)data-draftkit-context="custom_key"
: Optionally specify a custom key for contextdata-draftkit-context='{"key": "value"}'
: Add static context via JSONdata-draftkit-prompt="prompt_abc123"
: Mark field for generation with prompt tokendata-draftkit-button="field_name"
: Create custom button that targets a specific fielddata-draftkit-exclude
: Exclude sensitive fields from context collection
<\!-- Simple configuration via data attributes -->
<script src="https://app.draftkit.io/draftkit.js"
data-api-key="YOUR_API_KEY"
data-locale="en"
data-auto-buttons="true"
data-button-position="right">
</script>
DraftKit fires standard DOM events (similar to Turbo) that you can listen to:
// Listen to generation events
document.addEventListener('draftkit:before-generate', (event) => {
console.log('About to generate for:', event.detail.fieldName);
console.log('Context:', event.detail.context);
// Prevent generation if needed
if (\!validContext(event.detail.context)) {
event.preventDefault();
}
});
document.addEventListener('draftkit:generate', (event) => {
console.log('Generation completed:', event.detail.content);
});
document.addEventListener('draftkit:error', (event) => {
console.error('Generation failed:', event.detail.error);
});
document.addEventListener('draftkit:rate', (event) => {
console.log('User rated:', event.detail.rating);
});
When a field has data-draftkit-prompt
, a "Generate Draft" button will be automatically inserted:
- For
<textarea>
: Button appears in top-right corner of the field - For
<input>
: Button appears to the right of the field - For rich text editors: Button integrates with the editor's toolbar
Note: These endpoints will be mocked for this PR. Actual implementation will be done separately.
-
POST
/api/v1/drafts
- Request:
{ "context": { "field_name": "field_value", ... }, "prompt_id": "prompt_abc123", "target_field": "field_name" }
- Response:
{ "id": "generation_id", "content": "generated_text", "status": "success" }
- Request:
-
POST
/api/v1/ratings
- Request:
{ "generation_id": "generation_id", "rating": 1|0, // 1 = thumbs up, 0 = thumbs down "feedback": "optional feedback text" }
- Request:
<\!-- Include the library -->
<script src="https://app.draftkit.io/draftkit.js"
data-api-key="YOUR_API_KEY"></script>
<\!-- Product description form -->
<form>
<\!-- Context field (no button) -->
<label for="product_name">Product Name:</label>
<input type="text"
id="product_name"
name="product_name"
data-draftkit-context>
<\!-- Context field with custom key -->
<label for="category">Category:</label>
<select id="category"
name="category"
data-draftkit-context="product_category">
<option>Electronics</option>
<option>Clothing</option>
</select>
<\!-- Target field with auto-generated button -->
<label for="description">Description:</label>
<textarea id="description"
name="description"
data-draftkit-prompt="prompt_product_desc_v2"
rows="6"></textarea>
<\!-- ✨ Generate Draft button appears here automatically -->
<\!-- Sensitive field excluded from context -->
<input type="password"
name="api_secret"
data-draftkit-exclude>
<button type="submit">Submit</button>
</form>
<\!-- Add static context data -->
<textarea name="email_body"
data-draftkit-prompt="prompt_email_v1"
data-draftkit-context='{"tone": "professional", "max_length": 200}'
rows="10"></textarea>
<\!-- Custom styled button example -->
<form>
<input type="text"
name="company_name"
data-draftkit-context
placeholder="Company Name">
<input type="text"
name="industry"
data-draftkit-context
placeholder="Industry">
<\!-- Target field WITHOUT auto button -->
<textarea id="tagline"
name="tagline"
data-draftkit-prompt="prompt_tagline_v1"
data-draftkit-no-button
placeholder="Company tagline"></textarea>
<\!-- Custom button with your own design -->
<button type="button"
data-draftkit-button="tagline"
class="my-custom-btn">
<svg>...</svg> Generate Tagline with AI
</button>
</form>
<form id="blog-form">
<input name="topic" data-draftkit-context>
<textarea name="content"
data-draftkit-prompt="prompt_blog_v1"></textarea>
</form>
<script>
// Track generations
document.addEventListener('draftkit:before-generate', (event) => {
if (event.target.matches('#blog-form *')) {
analytics.track('AI Generation Started', {
field: event.detail.fieldName,
prompt: event.detail.promptId
});
}
});
// Show custom success message
document.addEventListener('draftkit:generate', (event) => {
showToast('Content generated successfully\!');
});
// Handle errors gracefully
document.addEventListener('draftkit:error', (event) => {
if (event.detail.error.code === 'rate_limit') {
showError('Too many requests. Please try again later.');
}
});
</script>
import React, { useEffect } from 'react';
function BlogForm() {
useEffect(() => {
// Load DraftKit script
const script = document.createElement('script');
script.src = 'https://app.draftkit.io/draftkit.js';
script.setAttribute('data-api-key', 'YOUR_API_KEY');
script.async = true;
document.body.appendChild(script);
// Listen to events
const handleGenerate = (event) => {
console.log('Generated:', event.detail);
};
document.addEventListener('draftkit:generate', handleGenerate);
return () => {
document.body.removeChild(script);
document.removeEventListener('draftkit:generate', handleGenerate);
};
}, []);
return (
<form>
{/* Context fields */}
<input
name="topic"
data-draftkit-context
placeholder="Blog Topic"
/>
{/* Add static context */}
<input
name="audience"
data-draftkit-context='{"importance": "high"}'
placeholder="Target Audience"
/>
{/* Auto button (DraftKit handles it) */}
<textarea
name="content"
data-draftkit-prompt="prompt_blog_v1"
placeholder="Blog Content"
rows="10"
/>
</form>
);
}
# app/controllers/draftkit_controller.rb
class DraftkitController < ApplicationController
def javascript
respond_to do |format|
format.js { render layout: false, content_type: 'text/javascript' }
end
end
end
# config/routes.rb
get '/draftkit.js', to: 'draftkit#javascript', as: :draftkit_js
The auto-generated buttons will have:
- Class:
draftkit-generate-btn
- Minimal, unobtrusive design
- Loading state animation
- Hover and active states
- Responsive sizing based on field size
/* Override default button styles */
.draftkit-generate-btn {
background: #your-color;
/* your custom styles */
}
/* Loading state */
.draftkit-generate-btn.loading {
/* custom loading styles */
}
/* Rating UI */
.draftkit-rating {
/* custom rating styles */
}
We'll use Rails' built-in JavaScript testing capabilities with a simple test runner. Tests will be in test/javascript/draftkit_test.js
:
// Test core functionality
- DraftKit initialization with valid API key
- DraftKit initialization without API key (should fail gracefully)
- Form field detection (data-draftkit-prompt)
- Context collection from marked fields
- Context exclusion (data-draftkit-exclude)
- Button creation and placement
- Custom button binding
- Event firing (before-generate, generate, error, rate)
- API request formatting
- Response handling and field updates
- Error handling and display
- Static context parsing from JSON
- Dynamic form handling (MutationObserver)
System tests will verify the full integration in test/system/draftkit_system_test.rb
:
class DraftkitSystemTest < ApplicationSystemTestCase
test "loads DraftKit library from Rails route" do
visit "/draftkit.js"
assert_match "window.DraftKit", page.body
end
test "automatic button generation" do
visit draftkit_demo_path
assert_selector ".draftkit-generate-btn"
end
test "generates content and updates field" do
visit draftkit_demo_path
fill_in "product_name", with: "Test Product"
click_button "Generate Draft"
assert_selector ".draftkit-loading"
assert_field "description", with: /generated content/
end
test "fires custom events" do
# Test event listeners work correctly
end
test "handles errors gracefully" do
# Test error scenarios
end
end
Test the Rails endpoint in test/controllers/draftkit_controller_test.rb
:
test "serves JavaScript with correct content type" do
get draftkit_js_path
assert_response :success
assert_equal "text/javascript", response.content_type
end
- Library loads without errors
- Buttons appear for all prompt fields
- Context collection works for all field types
- Custom buttons trigger generation
- Events fire in correct order
- Errors display user-friendly messages
- Works in Chrome, Firefox, Safari, Edge
- Works with Turbo navigation
- Rating UI appears and submits
Create a comprehensive demo page at /draftkit/demo
showing all features:
<\!-- app/views/static/draftkit_demo.html.erb -->
<div class="container">
<h1>DraftKit Demo</h1>
<\!-- Example 1: Basic Product Form -->
<section>
<h2>1. Basic Product Description</h2>
<form>
<input name="product_name" data-draftkit-context placeholder="Product Name">
<select name="category" data-draftkit-context>
<option>Electronics</option>
<option>Fashion</option>
</select>
<textarea name="description" data-draftkit-prompt="prompt_product_desc_v2"></textarea>
</form>
</section>
<\!-- Example 2: Custom Button -->
<section>
<h2>2. Custom Button Design</h2>
<form>
<input name="company" data-draftkit-context>
<textarea name="tagline" data-draftkit-prompt="prompt_tagline_v1" data-draftkit-no-button></textarea>
<button data-draftkit-button="tagline" class="btn-primary">✨ Generate</button>
</form>
</section>
<\!-- Example 3: Multiple Fields -->
<section>
<h2>3. Blog Post Generator</h2>
<form>
<input name="topic" data-draftkit-context>
<input name="title" data-draftkit-prompt="prompt_title_v1">
<textarea name="intro" data-draftkit-prompt="prompt_intro_v1"></textarea>
<textarea name="content" data-draftkit-prompt="prompt_content_v1"></textarea>
</form>
</section>
<\!-- Example 4: Static Context -->
<section>
<h2>4. Email with Tone</h2>
<form>
<input name="recipient" data-draftkit-context>
<textarea name="email"
data-draftkit-prompt="prompt_email_v1"
data-draftkit-context='{"tone": "professional", "length": "brief"}'>
</textarea>
</form>
</section>
<\!-- Example 5: Field Exclusion -->
<section>
<h2>5. Secure Form</h2>
<form>
<input name="username" data-draftkit-context>
<input type="password" name="api_key" data-draftkit-exclude>
<textarea name="bio" data-draftkit-prompt="prompt_bio_v1"></textarea>
</form>
</section>
<\!-- Event Monitor -->
<section>
<h2>Event Monitor</h2>
<div id="event-log"></div>
</section>
<script>
// Log all DraftKit events
['before-generate', 'generate', 'error', 'rate'].forEach(eventName => {
document.addEventListener(`draftkit:${eventName}`, (event) => {
const log = document.getElementById('event-log');
log.innerHTML += `<div>${new Date().toISOString()} - ${eventName}: ${JSON.stringify(event.detail)}</div>`;
});
});
</script>
</div>
# config/routes.rb
get '/draftkit/demo', to: 'static#draftkit_demo' if Rails.env.development?
- Library correctly identifies fields with prompt attributes and adds buttons
- Context collection works automatically using field names
- Static context can be added via JSON in data attributes
- Fields can be excluded from context with
data-draftkit-exclude
- Custom buttons can trigger generation for specific fields
- Standard DOM events are fired for all generation lifecycle stages
- Rails controller serves the JavaScript
- Generated content is correctly inserted into target fields
- Rating UI appears after generation
- Error states are handled gracefully
- Works with vanilla JavaScript and React
- All tests pass (unit, system, controller)
- Demo page showcases all features
- Core library is implemented with refined HTML API
- JavaScript file is served through Rails controller/view
- Event system is implemented using standard DOM events
- Mock API endpoints return sample data for testing
- Automatic button placement works correctly
- Custom button support is implemented
- Static context via JSON is supported
- Exclude attribute prevents fields from context collection
- JavaScript unit tests are written and passing
- Rails system tests verify full integration
- Controller tests verify endpoint behavior
- Demo page is created showing all examples
- Documentation is complete with multiple examples
- Cross-browser testing is complete
- Security review is completed
- Code follows DraftKit conventions and style guide
- Actual API endpoint implementation (will be done separately)
- CDN deployment and configuration
- Production build pipeline
- Cloudflare caching configuration
- Real LLM integration
- NPM package for single-page apps (future enhancement)