React Form Shield is a comprehensive anti-spam solution for React forms that provides multi-layered protection against bot submissions. It's designed to work with any React form library through dedicated adapters, includes both client-side and server-side validation, and maintains accessibility standards.
- 🛡️ Multi-layered Protection: Combines honeypot fields, time delay verification, and human verification challenges
- 🔄 Framework Agnostic: Works with any React form library (React Hook Form, Formik, etc.)
- đź§© Ready-to-Use Components: Pre-built UI components with customization options
- đź”’ Server Validation: Server-side validators for various backend environments
- 📝 TypeScript Support: Full TypeScript definitions for better developer experience
- ⚙️ Customizable Settings: Configurable features to meet different security needs
- đź§ Custom Challenge Types: Extensible system for creating your own verification challenges
- Installation
- Quick Start
- Usage Examples
- API Reference
- Server Integration
- Customization
- Security Considerations
- Contributing
- License
npm install react-form-shield
# or
yarn add react-form-shield
# or
pnpm add react-form-shield
import {
useFormShield,
ChallengeDialog,
HoneypotField,
} from "react-form-shield";
import { useForm } from "react-hook-form";
function ContactForm() {
const form = useForm();
const {
honeypotProps,
showChallengeDialog,
challenge,
challengeAnswer,
setChallengeAnswer,
handleChallengeSubmit,
validateSubmission,
getFormShieldData,
} = useFormShield();
const onSubmit = async (values) => {
const validationResult = validateSubmission(values);
if (validationResult.passed) {
// Submit form with anti-spam data
await fetch("/api/contact", {
method: "POST",
body: JSON.stringify({
...values,
...getFormShieldData(),
}),
});
}
};
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* Regular form fields */}
<input {...form.register("name")} placeholder="Name" />
<input {...form.register("email")} placeholder="Email" />
{/* Honeypot field (invisible to humans) */}
<HoneypotField {...honeypotProps} />
<button type="submit">Submit</button>
{/* Challenge dialog */}
<ChallengeDialog
open={showChallengeDialog}
challenge={challenge}
challengeAnswer={challengeAnswer}
setChallengeAnswer={setChallengeAnswer}
onSubmit={() => handleChallengeSubmit(onSubmit)}
/>
</form>
);
}
flowchart TD
FormShieldProvider[FormShieldProvider] --> Config[Configuration]
FormShieldProvider --> Hooks[Hooks]
Hooks --> useFormShield[useFormShield]
Hooks --> useHoneypot[useHoneypot]
Hooks --> useTimeDelay[useTimeDelay]
Hooks --> useChallenge[useChallenge]
useFormShield --> Components[Components]
Components --> ChallengeDialog[ChallengeDialog]
Components --> HoneypotField[HoneypotField]
Adapters[Framework Adapters] --> RHFAdapter[React Hook Form]
Adapters --> FormikAdapter[Formik]
Adapters --> NativeAdapter[Native React]
useFormShield --> Validators[Client Validators]
Validators --> HoneypotValidator[Honeypot Validation]
Validators --> TimeValidator[Time Delay Validation]
Validators --> ChallengeValidator[Challenge Validation]
sequenceDiagram
participant User
participant Form
participant FormShield
participant Server
User->>Form: Fill out form
Form->>FormShield: Track first interaction
FormShield->>FormShield: Start time tracking
User->>Form: Submit form
Form->>FormShield: Validate submission
alt Time delay not met
FormShield->>Form: Show challenge dialog
User->>Form: Complete challenge
Form->>FormShield: Validate challenge
FormShield->>Form: Challenge completed
end
Form->>Server: Submit form with anti-spam data
Server->>Server: Validate anti-spam data
Server->>Form: Return response
Form->>User: Show success/error message
import { useForm } from "react-hook-form";
import {
useFormShield,
withReactHookForm,
ChallengeDialog,
} from "react-form-shield";
function ContactForm() {
const form = useForm();
const formShield = useFormShield();
// Integrate with React Hook Form
const { register, formState, handleSubmit } = withReactHookForm(
form,
formShield
);
const onSubmit = async (data) => {
// Form data already includes anti-spam data
await fetch("/api/contact", {
method: "POST",
body: JSON.stringify(data),
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} placeholder="Name" />
<input {...register("email")} placeholder="Email" />
<button type="submit">Submit</button>
<ChallengeDialog {...formShield.challengeDialogProps} />
</form>
);
}
const express = require("express");
const { formShieldMiddleware } = require("react-form-shield/server");
const app = express();
app.use(express.json());
app.post("/api/contact", formShieldMiddleware(), (req, res) => {
// Form data is validated by middleware
// Process the form submission
res.json({ success: true });
});
app.listen(3000);
See the full API documentation for detailed information.
useFormShield(options)
: Main hook for form protectionuseHoneypot(options)
: Hook for honeypot field managementuseTimeDelay(options)
: Hook for time delay verificationuseChallenge(options)
: Hook for challenge generation and validation
ChallengeDialog
: Dialog for human verification challengesHoneypotField
: Hidden field for bot detectionFormShieldProvider
: Context provider for global configuration
formShieldMiddleware
: Express/Connect middlewarewithFormShield
: HOC for Next.js API routesvalidateFormShield
: Function for manual validation
react-form-shield provides multiple layers of protection, but it's important to understand its limitations:
- Client-side validation can be bypassed: Always implement server-side validation
- Honeypot fields can be detected: Sophisticated bots may identify and avoid honeypot fields
- Time delay can be spoofed: Bots can wait before submitting
- Challenges can be solved programmatically: Advanced bots may use OCR or AI to solve challenges
For maximum security, combine react-form-shield with other security measures like CAPTCHA, rate limiting, and IP blocking.
Honeypot fields are hidden form fields that are invisible to human users but are typically filled out by bots. When a submission contains data in these fields, it's flagged as a bot submission.
<HoneypotField name="random_field" />
Time delay verification ensures that the form wasn't submitted too quickly, which is a common characteristic of bot submissions. The library tracks the time between form load and submission, requiring a minimum delay.
// Configure minimum submission time
const formShield = useFormShield({
minSubmissionTime: 15, // 15 seconds
});
When time delay verification fails, the library can present human verification challenges, such as simple math problems or custom questions that are easy for humans but difficult for bots.
<ChallengeDialog
open={showChallengeDialog}
challenge={challenge}
challengeAnswer={challengeAnswer}
setChallengeAnswer={setChallengeAnswer}
onSubmit={handleChallengeSubmit}
/>
For forms that require stronger protection, the library supports multiple challenges to compensate for time deficits. The number of challenges required is calculated based on how much the submission time falls short of the minimum requirement.
// Configure multiple challenges
const formShield = useFormShield({
enableMultipleChallenges: true,
maxChallenges: 3,
challengeTimeValue: 5, // Each challenge is worth 5 seconds
});
The library supports custom challenge types, allowing you to create your own verification challenges beyond the built-in math and text challenges.
import { challengeRegistry } from "react-form-shield";
// Register a custom challenge type
challengeRegistry.register("image-captcha", {
// Function to generate a challenge
generate: () => ({
type: "image-captcha",
question: "Enter the characters shown in the image",
answer: "ABC123",
data: {
imageUrl: "https://example.com/captcha.jpg",
},
}),
// Optional custom component for rendering
component: ImageCaptchaComponent,
});
// Use in a form
const formShield = useFormShield({
preferredChallengeType: "image-captcha",
});
See the Custom Challenge Types Example for more details.
All client-side protections are duplicated on the server to prevent bypass attempts. The server-side middleware validates honeypot fields, time delay, and challenge completion.
// Express middleware
app.post(
"/api/contact",
formShieldMiddleware({
honeypotCheck: true,
timeDelayCheck: true,
challengeCheck: true,
}),
(req, res) => {
// Process valid submission
}
);
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.