A drop-in replacement for React Hook Form with AI-powered autofill and field suggestions. Supports Chrome Built-in AI, OpenAI, and custom AI providers with automatic fallback.
- AI-Powered Autofill: Generate realistic form data using AI
- Smart Field Suggestions: Get AI suggestions for individual fields with debounced blur events
- Multiple Provider Support: Chrome Built-in AI, OpenAI, Custom Server, or Browser AI
- Provider Fallback: Automatic fallback to next provider on failure
- Download Progress: Monitor Chrome AI model download progress
- Availability Checking: Check AI availability before use
- Global Configuration: Configure providers once with AIFormProvider
- Full TypeScript Support: Complete type definitions included
- Drop-in Replacement: 100% compatible with React Hook Form API
npm install react-hook-form-ai
# or
pnpm add react-hook-form-ai
# or
yarn add react-hook-form-aiimport { useForm } from 'react-hook-form-ai';
interface FormData {
firstName: string;
lastName: string;
email: string;
age: number;
}
function App() {
const {
register,
handleSubmit,
aiAutofill,
aiLoading,
aiAvailability,
formState: { errors },
} = useForm<FormData>();
const handleAutofill = async () => {
try {
await aiAutofill();
} catch (error) {
console.error('Autofill failed:', error);
}
};
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('firstName')} placeholder="First Name" />
<input {...register('lastName', { required: true })} placeholder="Last Name" />
{errors.lastName && <p>Last name is required.</p>}
<input {...register('email')} placeholder="Email" type="email" />
<input {...register('age', { pattern: /\d+/ })} placeholder="Age" />
{errors.age && <p>Please enter number for age.</p>}
<button
type="button"
onClick={handleAutofill}
disabled={aiLoading || !aiAvailability?.available}
>
{aiLoading ? 'Filling...' : 'AI Autofill'}
</button>
{aiAvailability && !aiAvailability.available && (
<p>AI is not available. Status: {aiAvailability.status}</p>
)}
<input type="submit" />
</form>
);
}Learn more about React Hook Form. This library only adds the AI part.
The AIFormProvider component allows you to configure AI providers globally for your entire application or a specific part of your component tree. This is the recommended approach for most applications.
import { AIFormProvider } from 'react-hook-form-ai';
import App from './App';
function Root() {
return (
<AIFormProvider
providers={[
{ type: 'chrome', priority: 10 },
{
type: 'openai',
apiKey: 'sk-...',
model: 'gpt-3.5-turbo',
priority: 5
},
{
type: 'custom',
apiUrl: 'https://your-api.com',
priority: 1
}
]}
executionOrder={['chrome', 'openai', 'custom']}
fallbackOnError={true}
>
<App />
</AIFormProvider>
);
}Configuration Options:
providers: Array of AI provider configurations (required)executionOrder: Array specifying the order to try providers. If not provided, providers are sorted by priority (highest first)fallbackOnError: Whentrue, automatically tries the next provider if one fails (default:true)enabled: Globally enable/disable AI features (default:true)debounceMs: Debounce time in milliseconds for AI suggestions (default:800)excludeFields: Array of field names to exclude from AI processing (default:[])
The Chrome Built-in AI provider uses Chrome's experimental on-device AI capabilities. This provider is privacy-friendly as all processing happens locally in the browser.
{
type: 'chrome',
priority: 10 // Optional: higher priority = tried first
}Features:
- ✅ No API key required
- ✅ Browser-based and privacy-friendly
- ✅ Free to use
⚠️ Requires Chrome 139+ with AI features enabled and Chrome Origin Tials Token⚠️ May require downloading the AI model on first use
Note: The AI model download requires user interaction. Use aiAvailability and aiDownloadProgress to handle the download flow gracefully.
The OpenAI provider connects to OpenAI's API for AI-powered form features.
{
type: 'openai',
apiKey: 'sk-...', // Required: Your OpenAI API key
model: 'gpt-3.5-turbo', // Optional: defaults to 'gpt-3.5-turbo'
organization: 'org-...', // Optional: Your OpenAI organization ID
apiUrl: 'https://api.openai.com/v1/chat/completions', // Optional: custom API URL for proxies
priority: 5
}Supported Models:
gpt-3.5-turbo(default) - Fast and cost-effectivegpt-4- More accurate but slower and more expensivegpt-4-turbo- Balance of speed and accuracy
Custom API URL:
You can use a custom apiUrl to route requests through a proxy or use OpenAI-compatible APIs:
{
type: 'openai',
apiKey: 'sk-...',
apiUrl: 'https://your-proxy.com/v1/chat/completions',
model: 'gpt-3.5-turbo'
}The Custom Server provider allows you to connect to your own AI backend or any custom API endpoint.
{
type: 'custom',
apiUrl: 'https://your-api.com',
headers: {
'Authorization': 'Bearer your-token',
'X-Custom-Header': 'value'
},
priority: 1
}Required API Endpoints:
Your custom server must implement these endpoints:
GET /health
Response: 200 OK
POST /api/suggest
Content-Type: application/json
Request Body:
{
"fieldName": "email",
"currentValue": "john@",
"formContext": { "firstName": "John", "lastName": "Doe" }
}
Response:
{
"suggestion": "john@example.com"
}
POST /api/autofill
Content-Type: application/json
Request Body:
{
"fields": ["firstName", "lastName", "email"],
"formContext": {}
}
Response:
{
"autofillData": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com"
}
}
You can override global provider settings for individual forms by passing options to the useForm hook:
import { useForm } from 'react-hook-form-ai';
function MyForm() {
const { register, aiAutofill } = useForm({
ai: {
enabled: true,
providers: [
{ type: 'openai', apiKey: 'sk-...', priority: 10 }
],
executionOrder: ['openai'],
fallbackOnError: false,
debounceMs: 500,
excludeFields: ['password', 'creditCard']
}
});
return (
<form>
<input {...register('username')} />
<input {...register('password')} type="password" />
<button type="button" onClick={() => aiAutofill()}>
AI Autofill
</button>
</form>
);
}Local options override global settings:
enabled: Enable/disable AI for this form onlyproviders: Use different providers for this formexecutionOrder: Custom provider order for this formfallbackOnError: Override fallback behaviordebounceMs: Custom debounce timingexcludeFields: Fields to exclude from AI processing (e.g., passwords, credit cards)
The useForm hook returns all standard React Hook Form properties plus the following AI-specific properties:
Indicates whether AI features are enabled for this form instance.
const { aiEnabled } = useForm({ ai: { enabled: true } });
console.log(aiEnabled); // trueTriggers AI-powered autofill for all form fields or specific fields.
Parameters:
fields(optional): Array of field names to autofill. If omitted, all fields are autofilled.
Returns: Promise<void> - Resolves when autofill is complete, rejects on error.
Example:
const { aiAutofill } = useForm<FormData>();
// Autofill all fields
await aiAutofill();
// Autofill specific fields only
await aiAutofill(['firstName', 'lastName']);Gets an AI suggestion for a specific field based on its current value and form context.
Parameters:
fieldName: The name of the field to get a suggestion for
Returns: Promise<string | null> - The suggested value, or null if no suggestion is available
Example:
const { aiSuggest, setValue } = useForm<FormData>();
const suggestion = await aiSuggest('email');
if (suggestion) {
setValue('email', suggestion);
}Indicates whether an AI operation (autofill or suggest) is currently in progress.
Example:
const { aiLoading, aiAutofill } = useForm();
<button onClick={() => aiAutofill()} disabled={aiLoading}>
{aiLoading ? 'Filling...' : 'AI Autofill'}
</button>Provides information about AI availability status. This is particularly useful for Chrome Built-in AI which may require model download.
Properties:
available:trueif AI is ready to usestatus: Current status string ('readily','downloadable','downloading','unavailable','error')needsDownload:trueif the AI model needs to be downloaded (Chrome AI only)
Example:
const { aiAvailability, aiAutofill } = useForm();
if (aiAvailability?.needsDownload) {
// User interaction required to start download
return <button onClick={() => aiAutofill()}>Download AI Model & Autofill</button>;
}
if (!aiAvailability?.available) {
return <p>AI unavailable: {aiAvailability?.status}</p>;
}Manually refreshes the AI availability status. Useful after user interactions or when checking if a download has completed.
Returns: Promise<void> - Resolves when availability check is complete
Example:
const { refreshAvailability, aiAvailability } = useForm();
useEffect(() => {
const interval = setInterval(async () => {
if (aiAvailability?.status === 'downloading') {
await refreshAvailability();
}
}, 2000);
return () => clearInterval(interval);
}, [aiAvailability?.status]);Download progress percentage (0-100) when the Chrome AI model is being downloaded. null when not downloading.
Example:
const { aiDownloadProgress } = useForm();
{aiDownloadProgress !== null && (
<div>
<progress value={aiDownloadProgress} max={100} />
<span>{aiDownloadProgress}% downloaded</span>
</div>
)}Configuration options for AI features, passed to the useForm hook via the ai property.
interface AIFormOptions {
enabled?: boolean;
apiUrl?: string;
debounceMs?: number;
excludeFields?: string[];
autoCheckAvailability?: boolean;
providers?: AIProvider[];
executionOrder?: AIProviderType[];
fallbackOnError?: boolean;
}enabled?: boolean
- Default:
true - Enable or disable AI features for this form
- Example:
{ ai: { enabled: false } }
apiUrl?: string
- Default:
'http://localhost:3001' - Fallback API endpoint for custom server provider
- Example:
{ ai: { apiUrl: 'https://api.example.com' } }
debounceMs?: number
- Default:
800 - Debounce time in milliseconds for AI suggestions on field blur
- Example:
{ ai: { debounceMs: 500 } }
excludeFields?: string[]
- Default:
[] - Array of field names to exclude from AI processing (e.g., passwords, credit cards)
- Example:
{ ai: { excludeFields: ['password', 'ssn', 'creditCard'] } }
autoCheckAvailability?: boolean
- Default:
true - Automatically check AI availability when the form mounts
- Example:
{ ai: { autoCheckAvailability: false } }
providers?: AIProvider[]
- Default: Inherited from
AIFormProviderorundefined - Override AI providers for this specific form
- Example:
{ ai: { providers: [{ type: 'openai', apiKey: 'sk-...' }] } }
executionOrder?: AIProviderType[]
- Default: Inherited from
AIFormProvideror sorted by priority - Override the order in which providers are tried
- Example:
{ ai: { executionOrder: ['chrome', 'openai'] } }
fallbackOnError?: boolean
- Default:
true - Automatically try the next provider if one fails
- Example:
{ ai: { fallbackOnError: false } }
Complete Example:
const form = useForm<FormData>({
ai: {
enabled: true,
debounceMs: 500,
excludeFields: ['password', 'creditCard'],
autoCheckAvailability: true,
providers: [
{ type: 'chrome', priority: 10 },
{ type: 'openai', apiKey: 'sk-...', priority: 5 }
],
executionOrder: ['chrome', 'openai'],
fallbackOnError: true
}
});The library supports multiple AI provider types, each with its own configuration interface.
Union type of all supported provider types:
type AIProviderType = 'chrome' | 'openai' | 'custom' | 'browser';Configuration for Chrome Built-in AI provider.
interface ChromeAIConfig {
type: 'chrome';
enabled?: boolean;
priority?: number;
}Example:
const chromeProvider: ChromeAIConfig = {
type: 'chrome',
priority: 10
};Properties:
type: Must be'chrome'enabled: Optional. Set tofalseto disable this providerpriority: Optional. Higher values are tried first (default: 0)
Configuration for OpenAI API provider.
interface OpenAIConfig {
type: 'openai';
apiKey: string;
apiUrl?: string;
model?: string;
organization?: string;
enabled?: boolean;
priority?: number;
}Example:
const openaiProvider: OpenAIConfig = {
type: 'openai',
apiKey: 'sk-...',
model: 'gpt-4',
organization: 'org-...',
priority: 5
};Properties:
type: Must be'openai'apiKey: Required. Your OpenAI API keyapiUrl: Optional. Custom API endpoint (default: OpenAI's API)model: Optional. Model to use (default:'gpt-3.5-turbo')organization: Optional. Your OpenAI organization IDenabled: Optional. Set tofalseto disable this providerpriority: Optional. Higher values are tried first (default: 0)
Configuration for custom AI server provider.
interface CustomServerConfig {
type: 'custom';
apiUrl: string;
headers?: Record<string, string>;
enabled?: boolean;
priority?: number;
}Example:
const customProvider: CustomServerConfig = {
type: 'custom',
apiUrl: 'https://your-api.com',
headers: {
'Authorization': 'Bearer token',
'X-Custom-Header': 'value'
},
priority: 1
};Properties:
type: Must be'custom'apiUrl: Required. Your custom API endpointheaders: Optional. Custom HTTP headers for requestsenabled: Optional. Set tofalseto disable this providerpriority: Optional. Higher values are tried first (default: 0)
Configuration for browser-based AI provider.
interface BrowserAIConfig {
type: 'browser';
apiUrl: string;
headers?: Record<string, string>;
enabled?: boolean;
priority?: number;
}Example:
const browserProvider: BrowserAIConfig = {
type: 'browser',
apiUrl: 'https://browser-ai.example.com',
priority: 3
};Properties:
type: Must be'browser'apiUrl: Required. Browser AI service endpointheaders: Optional. Custom HTTP headers for requestsenabled: Optional. Set tofalseto disable this providerpriority: Optional. Higher values are tried first (default: 0)
The AIProvider type is a union of all provider configuration types:
type AIProvider = ChromeAIConfig | OpenAIConfig | CustomServerConfig | BrowserAIConfig;Usage in AIFormProvider:
const providers: AIProvider[] = [
{ type: 'chrome', priority: 10 },
{ type: 'openai', apiKey: 'sk-...', model: 'gpt-4', priority: 5 },
{ type: 'custom', apiUrl: 'https://api.example.com', priority: 1 }
];
<AIFormProvider providers={providers}>
<App />
</AIFormProvider>This example demonstrates how to configure multiple AI providers with priority-based execution and automatic fallback when a provider fails.
import { AIFormProvider, useForm } from 'react-hook-form-ai';
// Root component with provider configuration
function Root() {
return (
<AIFormProvider
providers={[
// Chrome AI: Highest priority, free and privacy-friendly
{
type: 'chrome',
priority: 10
},
// OpenAI: Fallback option with good accuracy
{
type: 'openai',
apiKey: process.env.REACT_APP_OPENAI_KEY || '',
model: 'gpt-3.5-turbo',
priority: 5
},
// Custom server: Lowest priority fallback
{
type: 'custom',
apiUrl: 'https://your-ai-backend.com',
headers: {
'Authorization': `Bearer ${process.env.REACT_APP_CUSTOM_TOKEN}`
},
priority: 1
}
]}
executionOrder={['chrome', 'openai', 'custom']}
fallbackOnError={true}
>
<App />
</AIFormProvider>
);
}
// Form component that uses the configured providers
function App() {
const {
register,
handleSubmit,
aiAutofill,
aiLoading,
aiAvailability
} = useForm<{
name: string;
email: string;
company: string;
}>();
const [error, setError] = React.useState<string | null>(null);
const handleAutofill = async () => {
setError(null);
try {
// Will try Chrome first, then OpenAI, then Custom if previous ones fail
await aiAutofill();
} catch (err) {
setError('All AI providers failed. Please fill the form manually.');
console.error('Autofill error:', err);
}
};
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<input {...register('name')} placeholder="Full Name" />
<input {...register('email')} placeholder="Email" type="email" />
<input {...register('company')} placeholder="Company" />
<button
type="button"
onClick={handleAutofill}
disabled={aiLoading || !aiAvailability?.available}
>
{aiLoading ? 'Filling...' : 'AI Autofill'}
</button>
{error && <p style={{ color: 'red' }}>{error}</p>}
{aiAvailability && !aiAvailability.available && (
<p>AI Status: {aiAvailability.status}</p>
)}
<button type="submit">Submit</button>
</form>
);
}How Fallback Works:
-
Chrome AI is tried first (priority: 10)
- If Chrome AI is unavailable or fails, automatically falls back to OpenAI
-
OpenAI is tried second (priority: 5)
- If OpenAI fails (e.g., API key invalid, rate limit), falls back to Custom server
-
Custom server is tried last (priority: 1)
- If all providers fail, the promise rejects and you can handle the error
Benefits:
- Free Chrome AI when available
- Reliable fallback to cloud providers
- Graceful degradation
- No single point of failure
This example shows how to use AI suggestions for individual fields, with custom debounce timing and field exclusions for sensitive data.
import { useForm } from 'react-hook-form-ai';
import { useState } from 'react';
interface ProfileForm {
username: string;
email: string;
bio: string;
password: string;
website: string;
}
function ProfileEditor() {
const {
register,
handleSubmit,
aiSuggest,
setValue,
watch
} = useForm<ProfileForm>({
ai: {
enabled: true,
debounceMs: 500, // Faster suggestions (default is 800ms)
excludeFields: ['password'], // Never send password to AI
providers: [
{ type: 'chrome', priority: 10 },
{ type: 'openai', apiKey: process.env.REACT_APP_OPENAI_KEY || '', priority: 5 }
]
}
});
const [suggestions, setSuggestions] = useState<Record<string, string>>({});
const [loadingField, setLoadingField] = useState<string | null>(null);
// Get AI suggestion for a specific field
const getSuggestion = async (fieldName: keyof ProfileForm) => {
setLoadingField(fieldName);
try {
const suggestion = await aiSuggest(fieldName);
if (suggestion) {
setSuggestions(prev => ({ ...prev, [fieldName]: suggestion }));
}
} catch (error) {
console.error(`Failed to get suggestion for ${fieldName}:`, error);
} finally {
setLoadingField(null);
}
};
// Accept a suggestion and apply it to the field
const acceptSuggestion = (fieldName: keyof ProfileForm) => {
const suggestion = suggestions[fieldName];
if (suggestion) {
setValue(fieldName, suggestion);
setSuggestions(prev => {
const updated = { ...prev };
delete updated[fieldName];
return updated;
});
}
};
const currentValues = watch();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<div>
<label>Username</label>
<input {...register('username')} placeholder="johndoe" />
<button
type="button"
onClick={() => getSuggestion('username')}
disabled={loadingField === 'username'}
>
{loadingField === 'username' ? '...' : '✨ Suggest'}
</button>
{suggestions.username && (
<div style={{ background: '#f0f0f0', padding: '8px', margin: '4px 0' }}>
<strong>Suggestion:</strong> {suggestions.username}
<button type="button" onClick={() => acceptSuggestion('username')}>
✓ Accept
</button>
<button type="button" onClick={() => setSuggestions(prev => {
const updated = { ...prev };
delete updated.username;
return updated;
})}>
✗ Dismiss
</button>
</div>
)}
</div>
<div>
<label>Email</label>
<input {...register('email')} placeholder="john@example.com" type="email" />
<button
type="button"
onClick={() => getSuggestion('email')}
disabled={loadingField === 'email'}
>
{loadingField === 'email' ? '...' : '✨ Suggest'}
</button>
{suggestions.email && (
<div style={{ background: '#f0f0f0', padding: '8px', margin: '4px 0' }}>
<strong>Suggestion:</strong> {suggestions.email}
<button type="button" onClick={() => acceptSuggestion('email')}>
✓ Accept
</button>
<button type="button" onClick={() => setSuggestions(prev => {
const updated = { ...prev };
delete updated.email;
return updated;
})}>
✗ Dismiss
</button>
</div>
)}
</div>
<div>
<label>Bio</label>
<textarea {...register('bio')} placeholder="Tell us about yourself..." rows={4} />
<button
type="button"
onClick={() => getSuggestion('bio')}
disabled={loadingField === 'bio'}
>
{loadingField === 'bio' ? '...' : '✨ Improve with AI'}
</button>
{suggestions.bio && (
<div style={{ background: '#f0f0f0', padding: '8px', margin: '4px 0' }}>
<strong>Improved version:</strong>
<p>{suggestions.bio}</p>
<button type="button" onClick={() => acceptSuggestion('bio')}>
✓ Accept
</button>
<button type="button" onClick={() => setSuggestions(prev => {
const updated = { ...prev };
delete updated.bio;
return updated;
})}>
✗ Dismiss
</button>
</div>
)}
</div>
<div>
<label>Password</label>
<input
{...register('password')}
type="password"
placeholder="Enter secure password"
/>
{/* No AI suggestion button for password - it's excluded */}
<small style={{ color: '#666' }}>
🔒 Password is excluded from AI processing for security
</small>
</div>
<div>
<label>Website</label>
<input {...register('website')} placeholder="https://example.com" />
<button
type="button"
onClick={() => getSuggestion('website')}
disabled={loadingField === 'website'}
>
{loadingField === 'website' ? '...' : '✨ Suggest'}
</button>
{suggestions.website && (
<div style={{ background: '#f0f0f0', padding: '8px', margin: '4px 0' }}>
<strong>Suggestion:</strong> {suggestions.website}
<button type="button" onClick={() => acceptSuggestion('website')}>
✓ Accept
</button>
<button type="button" onClick={() => setSuggestions(prev => {
const updated = { ...prev };
delete updated.website;
return updated;
})}>
✗ Dismiss
</button>
</div>
)}
</div>
<button type="submit">Save Profile</button>
</form>
);
}Key Features:
- Custom Debounce: Set to 500ms for faster suggestions (default is 800ms)
- Field Exclusion: Password field is excluded from AI processing for security
- User Control: Users can review suggestions before accepting them
- Context-Aware: AI considers other field values when making suggestions
- Individual Field Targeting: Get suggestions for specific fields on demand
Use Cases:
- Improving email formatting based on username
- Enhancing bio text for better readability
- Suggesting professional website URLs
- Formatting names consistently
Chrome's Built-in AI requires downloading a language model (~1-2GB) on first use. This example shows how to handle the download flow gracefully with progress tracking.
import { useForm } from 'react-hook-form-ai';
import { useEffect, useState } from 'react';
interface FormData {
name: string;
email: string;
message: string;
}
function ContactForm() {
const {
register,
handleSubmit,
aiAutofill,
aiLoading,
aiAvailability,
refreshAvailability,
aiDownloadProgress
} = useForm<FormData>({
ai: {
providers: [{ type: 'chrome', priority: 10 }],
autoCheckAvailability: true
}
});
const [downloadStarted, setDownloadStarted] = useState(false);
// Poll availability during download
useEffect(() => {
if (aiAvailability?.status === 'downloading') {
const interval = setInterval(async () => {
await refreshAvailability();
}, 2000); // Check every 2 seconds
return () => clearInterval(interval);
}
}, [aiAvailability?.status, refreshAvailability]);
const handleAutofillClick = async () => {
// If model needs download, this will trigger the download
if (aiAvailability?.needsDownload) {
setDownloadStarted(true);
}
try {
await aiAutofill();
} catch (error) {
console.error('Autofill failed:', error);
}
};
// Render different UI based on availability status
const renderAIStatus = () => {
if (!aiAvailability) {
return <p>Checking AI availability...</p>;
}
switch (aiAvailability.status) {
case 'readily':
return (
<button
type="button"
onClick={handleAutofillClick}
disabled={aiLoading}
>
{aiLoading ? 'Filling...' : '✨ AI Autofill'}
</button>
);
case 'downloadable':
return (
<div>
<button
type="button"
onClick={handleAutofillClick}
disabled={aiLoading}
>
📥 Download AI Model & Autofill
</button>
<p style={{ fontSize: '0.9em', color: '#666' }}>
First-time setup: ~1-2GB download required
</p>
</div>
);
case 'downloading':
return (
<div>
<p>Downloading AI model...</p>
{aiDownloadProgress !== null && (
<div>
<progress
value={aiDownloadProgress}
max={100}
style={{ width: '100%', height: '20px' }}
/>
<p>{Math.round(aiDownloadProgress)}% complete</p>
</div>
)}
<small style={{ color: '#666' }}>
This is a one-time download. Please keep this tab open.
</small>
</div>
);
case 'unavailable':
return (
<div>
<p style={{ color: '#999' }}>
❌ Chrome AI is not available in this browser
</p>
<small>
Requires Chrome 127+ with AI features enabled.
<br />
Visit <a href="chrome://flags/#optimization-guide-on-device-model" target="_blank">
chrome://flags/#optimization-guide-on-device-model
</a> to enable.
</small>
</div>
);
case 'error':
return (
<div>
<p style={{ color: '#d00' }}>⚠️ AI availability check failed</p>
<button type="button" onClick={() => refreshAvailability()}>
🔄 Retry
</button>
</div>
);
default:
return <p>Unknown AI status: {aiAvailability.status}</p>;
}
};
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<h2>Contact Us</h2>
<div>
<label>Name</label>
<input {...register('name')} placeholder="Your name" />
</div>
<div>
<label>Email</label>
<input {...register('email')} placeholder="your@email.com" type="email" />
</div>
<div>
<label>Message</label>
<textarea {...register('message')} placeholder="Your message..." rows={5} />
</div>
<div style={{ margin: '20px 0', padding: '15px', background: '#f5f5f5', borderRadius: '8px' }}>
{renderAIStatus()}
</div>
<button type="submit">Send Message</button>
</form>
);
}Best Practices:
- Check availability on mount - Use
autoCheckAvailability: true(default) - Show download progress - Display
aiDownloadProgressduring download - Require user interaction - Chrome requires user action to start download
- Poll during download - Use
refreshAvailability()to update status - Provide fallback - Configure alternative providers for unsupported browsers
- Clear messaging - Explain the one-time download requirement
Download Requirements:
⚠️ Requires user interaction (button click) to start download⚠️ Download size: ~1-2GB (one-time only)⚠️ User must keep the tab open during download- ✅ Model is cached locally after download
- ✅ Subsequent uses are instant
The Chrome Built-in AI provider requires Chrome version 127 or higher with experimental AI features enabled. This provider offers privacy-friendly, on-device AI processing at no cost.
- Update Chrome: Ensure you're running Chrome 139 or later
- Enable AI Features: Visit
chrome://flags/#optimization-guide-on-device-modeland set it to "Enabled" - Restart Browser: Relaunch Chrome for changes to take effect
When aiAvailability.needsDownload is true, you should:
- Inform the user about the one-time download requirement
- Require user action - provide a clear button to trigger the download
- Display progress using
aiDownloadProgressduring download - Keep user informed - explain they need to keep the tab open
Example:
const { aiAvailability, aiDownloadProgress, aiAutofill } = useForm({
ai: { providers: [{ type: 'chrome' }] }
});
if (aiAvailability?.needsDownload) {
return (
<div>
<p>Chrome AI requires a one-time model download (~1-2GB)</p>
<button onClick={() => aiAutofill()}>
📥 Download AI Model & Start
</button>
</div>
);
}
if (aiAvailability?.status === 'downloading') {
return (
<div>
<p>Downloading AI model... Please keep this tab open.</p>
<progress value={aiDownloadProgress || 0} max={100} />
<p>{Math.round(aiDownloadProgress || 0)}% complete</p>
</div>
);
}For browsers that don't support Chrome AI, configure fallback providers to ensure your forms remain functional:
<AIFormProvider
providers={[
{ type: 'chrome', priority: 10 }, // Try Chrome AI first
{ type: 'openai', apiKey: 'sk-...', priority: 5 }, // Fallback to OpenAI
{ type: 'custom', apiUrl: 'https://your-api.com', priority: 1 } // Final fallback
]}
fallbackOnError={true}
>
<App />
</AIFormProvider>Fallback Behavior:
- If Chrome AI is unavailable, the library automatically tries the next provider in the execution order
- Users on unsupported browsers (Safari, Firefox, older Chrome) will seamlessly use alternative providers
- No code changes needed - fallback is automatic when
fallbackOnError={true}
You can check AI availability and handle different states in your component:
const { aiAvailability, refreshAvailability } = useForm();
useEffect(() => {
// Check availability on mount
refreshAvailability();
}, []);
if (!aiAvailability) {
return <p>Checking AI availability...</p>;
}
if (aiAvailability.status === 'unavailable') {
return (
<div>
<p>Chrome AI is not available in this browser.</p>
<p>Using fallback AI provider...</p>
</div>
);
}
if (aiAvailability.available) {
return <button onClick={() => aiAutofill()}>✨ AI Autofill</button>;
}Recommendation: Always configure at least one fallback provider (OpenAI or Custom Server) to ensure your forms work across all browsers.
We welcome contributions! Please see our Contributing Guide for details on how to get started, coding standards, and the pull request process.
This library is built on top of the excellent React Hook Form library. All credit for the core form management functionality goes to the React Hook Form team. This library simply adds AI-powered features on top of their solid foundation.
- React Hook Form Documentation - Learn about the underlying form library
- Chrome Built-in AI Documentation - Official Chrome AI documentation
- Contributing Guide - How to contribute to this project
MIT © Saad Bazaz
This project is licensed under the MIT License - see the LICENSE file for details.