recaptz
v2.0.0
Published
<div align="center">
Maintainers
Readme
ReCAPTZ
Modern, Lightweight CAPTCHA for React
A powerful, zero-dependency CAPTCHA library with 6 interactive types, full accessibility support, and beautiful animations - all running entirely client-side.
🚀 Getting Started • 📖 Documentation • 🎮 Demo • 💬 Community
✨ Features
🎯 Six CAPTCHA Types
- Text (Numbers, Letters, Mixed)
- Slider Puzzle
- Math Challenge
- Pattern Recognition
- Custom Characters
♿ Accessibility First
- WCAG 2.1 AA Compliant
- Screen Reader Support
- Keyboard Navigation
- Audio Feedback (TTS)
⚡ Performance
- Zero Dependencies
- < 50KB Minified
- Client-Side Only
- SSR Compatible
🎨 Customization
- Dark Mode Support
- Custom Themes
- 18n & RTL Support
- Custom Validators
Why ReCAPTZ?
✅ No External APIs - Works completely offline, no Google/third-party services
✅ Zero Configuration - Drop-in component, works out of the box
✅ Developer Friendly - TypeScript, React Hooks, comprehensive docs
✅ Production Ready - Battle-tested, used in production apps
📦 Installation
# npm
npm install recaptz
# yarn
yarn add recaptz
# pnpm
pnpm add recaptz
# bun
bun add recaptz🚀 Quick Start
import { Captcha } from "recaptz";
import { useState } from "react";
function App() {
const [isVerified, setIsVerified] = useState(false);
return (
<div>
<Captcha
type="mixed"
length={6}
onValidate={setIsVerified}
showSuccessAnimation
/>
<button disabled={!isVerified}>Submit</button>
</div>
);
}That's it! 🎉 No API keys, no server setup, no configuration needed.
🎮 CAPTCHA Types
ReCAPTZ offers 6 distinct CAPTCHA types to suit different security needs and user experiences.
📝 Text-Based CAPTCHAs
Perfect for traditional form protection with customizable character sets.
<Captcha
type="numbers"
length={4}
onValidate={(isValid) => console.log("Verified:", isValid)}
/>Use Case: Login forms, simple verifications
Difficulty: Easy
Accessibility: Audio support included
<Captcha type="letters" length={6} caseSensitive={false} />Use Case: Registration forms
Difficulty: Medium
Accessibility: Audio support included
<Captcha type="mixed" length={6} caseSensitive={true} showSuccessAnimation />Use Case: High-security forms, payment pages
Difficulty: Hard
Accessibility: Audio support included
<Captcha
customCharacters="ABCDEF123456"
length={5}
caseSensitive={true}
validationRules={{
customValidator: (value) => /^[A-F0-9]+$/.test(value),
}}
/>Use Case: Specialized forms, API key verification
Difficulty: Customizable
Accessibility: Audio support included
🧩 Slider Puzzle CAPTCHA
Interactive drag-and-drop puzzle solving - engaging and bot-resistant.
<Captcha
type="slider"
sliderConfig={{
width: 320,
height: 180,
pieceSize: 42,
tolerance: 12,
enableShadow: true,
}}
showSuccessAnimation
showConfetti
onValidate={(isValid) => console.log("Puzzle solved:", isValid)}
/>Features:
- 🎨 Auto-generated beautiful background images (via Pexels API)
- 🎯 Precise validation with configurable tolerance
- 📱 Touch-friendly for mobile devices
- 🌓 Dark mode support
Override automatic images with your own:
<Captcha
type="slider"
sliderConfig={{
// Single custom image
backgroundImage: "https://your-domain.com/puzzle.jpg",
// Or multiple images for variety
backgroundImages: [
"https://your-domain.com/puzzle1.jpg",
"https://your-domain.com/puzzle2.jpg",
"https://your-domain.com/puzzle3.jpg",
],
}}
/>Use Case: Modern web apps, mobile-first sites
Difficulty: Medium
Bot Resistance: High
🧮 Math Challenge CAPTCHA
Solve simple arithmetic problems - human-friendly, bot-resistant.
<Captcha
type="math"
mathConfig={{
difficulty: "medium",
operations: ["addition", "subtraction", "multiplication"],
range: { min: 1, max: 20 },
}}
onValidate={(isValid) => console.log("Math solved:", isValid)}
/>Difficulty Levels:
| Level | Operations | Range | Example |
| ---------- | ---------- | ----- | ------------ |
| Easy | +, − | 1-10 | 3 + 5 = ? |
| Medium | +, −, × | 1-20 | 7 × 3 = ? |
| Hard | +, −, ×, ÷ | 1-50 | 48 ÷ 6 = ? |
Advanced Configuration:
<Captcha
type="math"
mathConfig={{
difficulty: "hard",
operations: ["addition", "subtraction", "multiplication", "division"],
range: { min: 1, max: 50 },
allowDecimals: false,
showHint: true,
}}
enableAudio
darkMode
/>Use Case: Educational sites, family-friendly apps, quick verifications
Difficulty: Easy to Hard (configurable)
Accessibility: Excellent - natural language friendly
🎨 Pattern Recognition CAPTCHA
Identify patterns in shapes, colors, rotations, and sizes - visual and engaging.
<Captcha
type="pattern"
patternConfig={{
difficulty: "medium",
gridSize: 6,
patternTypes: ["shape", "color", "rotation", "size"],
}}
onValidate={(isValid) => console.log("Pattern found:", isValid)}
/>Pattern Types:
Shape
Find the different shape(circles, squares, triangles, stars, diamonds, hexagons, hearts)
Color
Find the different color(9 vibrant colors)
Rotation
Find the differently rotated shape(0°, 45°, 90°, 135°, 180°)
Size
Find the larger/smaller shape(relative sizing)
Mixed
Combination of multiple pattern types(ultimate challenge)
Grid Sizes:
4 items- Easy (2×2 grid)6 items- Medium (2×3 grid)9 items- Hard (3×3 grid)
Advanced Configuration:
<Captcha
type="pattern"
patternConfig={{
difficulty: "hard",
gridSize: 9,
patternTypes: ["shape", "color", "rotation", "size", "mixed"],
shapes: ["circle", "square", "triangle", "star", "diamond"],
colors: ["#3b82f6", "#ef4444", "#10b981", "#f59e0b"],
}}
darkMode
showSuccessAnimation
i18n={{
instruction: "Find the pattern!",
selectDifferent: "Select the different one",
showHint: "Need help?",
}}
/>Use Case: Gaming sites, creative apps, visual learners
Difficulty: Easy to Hard (configurable)
Accessibility: Visual-first (audio description support planned)
Bot Resistance: Very High
⚙️ Advanced Configuration
Combine features for enhanced security and UX:
<Captcha
type="mixed"
length={6}
// Security
maxAttempts={3}
refreshInterval={60}
caseSensitive
// UX Enhancement
autoFocus
enableAudio
showSuccessAnimation
showConfetti
// Callbacks
onValidate={(isValid) => console.log("Valid:", isValid)}
onFail={() => alert("Too many attempts!")}
onSuccess={() => console.log("Success!")}
// Theming
darkMode
className="my-custom-captcha"
/>🎣 Custom Hook Usage
Build fully custom CAPTCHA UIs using the useCaptchaState hook.
Basic Hook Example
import { useCaptchaState, CaptchaProvider } from "recaptz";
function CustomCaptcha() {
const {
captchaText,
userInput,
setUserInput,
validate,
refresh,
isValid,
error,
} = useCaptchaState();
return (
<div className="custom-captcha">
<div className="captcha-display">{captchaText}</div>
<input
type="text"
value={userInput}
onChange={(e) => setUserInput(e.target.value)}
placeholder="Enter the code"
/>
<div className="captcha-actions">
<button onClick={validate}>Verify</button>
<button onClick={refresh}>Refresh</button>
</div>
{isValid && <div className="success">✓ Verified!</div>}
{error && <div className="error">{error}</div>}
</div>
);
}
function App() {
return (
<CaptchaProvider type="mixed" length={6}>
<CustomCaptcha />
</CaptchaProvider>
);
}Hook API Reference
interface CaptchaState {
captchaText: string; // Current CAPTCHA text
userInput: string; // User's input value
setUserInput: (input: string) => void; // Update user input
validate: () => Promise<boolean>; // Validate the input
refresh: () => Promise<void>; // Generate new CAPTCHA
isValid: boolean; // Current validation state
error: string | null; // Current error message
attempts: number; // Failed attempt count
isLoading: boolean; // Loading state
}Advanced Hook Example
function AdvancedCustomCaptcha() {
const { captchaText, validate, refresh, isValid, attempts } =
useCaptchaState();
const [input, setInput] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const result = await validate();
if (result) {
console.log("Success!");
} else if (attempts >= 3) {
console.log("Too many attempts");
await refresh();
}
};
return <form onSubmit={handleSubmit}>{/* Your custom UI */}</form>;
}Validation Rules
Configure custom validation with the ValidationRules interface:
interface ValidationRules {
minLength?: number;
maxLength?: number;
allowedCharacters?: string;
required?: boolean;
caseSensitive?: boolean;
customValidator?: (value: string) => boolean | string;
}
// Example with complex validation
<Captcha
validationRules={{
required: true,
minLength: 4,
maxLength: 8,
allowedCharacters: "ABCDEF123456",
customValidator: (value) => {
const hasLetter = /[A-F]/.test(value);
const hasNumber = /[1-6]/.test(value);
if (!hasLetter) return "Must contain at least one letter";
if (!hasNumber) return "Must contain at least one number";
return true;
},
}}
/>;Styling and Theming
Custom Styles
<Captcha
className="my-custom-captcha"
customStyles={{
backgroundColor: '#f8f9fa',
borderRadius: '12px',
padding: '20px',
boxShadow: '0 4px 12px rgba(0,0,0,0.1)'
}}
/>
// Dark theme
<Captcha
darkMode={true}
customStyles={{
backgroundColor: '#1a1a1a',
border: '1px solid #333',
borderRadius: '8px',
}}
/>CSS Customization
.my-custom-captcha {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.my-custom-captcha input {
border-radius: 8px;
border: 2px solid #e1e5e9;
padding: 12px;
font-size: 16px;
}
.my-custom-captcha button {
background: #4caf50;
color: white;
border: none;
border-radius: 8px;
padding: 12px 24px;
cursor: pointer;
transition: all 0.2s;
}Success Animations
Configure success animations and confetti effects:
interface ConfettiOptions {
particleCount?: number; // Number of particles (default: 100)
spread?: number; // Spread angle in degrees (default: 45)
origin?: { x?: number; y?: number }; // Origin point (default: center)
colors?: string[]; // Custom colors array
gravity?: number; // Gravity effect (default: 1)
scalar?: number; // Particle size multiplier (default: 1)
duration?: number; // Animation duration in ms (default: 3000)
}
<Captcha
showConfetti={true}
confettiOptions={{
particleCount: 200,
spread: 70,
colors: ["#ff0000", "#00ff00", "#0000ff"],
duration: 5000,
gravity: 0.8,
scalar: 1.2,
}}
/>;Custom Components
Replace default components with custom implementations:
<Captcha
loadingComponent={
<div className="flex items-center gap-2">
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600"></div>
<span>Generating CAPTCHA...</span>
</div>
}
successComponent={
<div className="flex items-center gap-2 text-green-600">
<span className="font-semibold">Verification Successful!</span>
</div>
}
errorComponent={({ error, severity }) => (
<div
className={`p-3 rounded-lg ${
severity === "high"
? "bg-red-100 text-red-800"
: severity === "medium"
? "bg-yellow-100 text-yellow-800"
: "bg-blue-100 text-blue-800"
}`}
>
{error}
</div>
)}
/>Event Handling
Handle CAPTCHA events for analytics and debugging:
const handleCaptchaEvents = {
onChange: (value) => console.log("Input changed:", value),
onValidate: (isValid) => console.log("Validation result:", isValid),
onRefresh: () => console.log("CAPTCHA refreshed"),
onAudioPlay: () => console.log("Audio played"),
onError: (error) => console.error("CAPTCHA error:", error),
onFail: () => console.log("Validation failed"),
onSuccess: () => console.log("Validation succeeded"),
};
<Captcha
{...handleCaptchaEvents}
maxAttempts={3}
showSuccessAnimation={true}
/>;Internationalization
Multi-Language Support
// German
<Captcha
i18n={{
securityCheck: "Sicherheitsüberprüfung",
listenToCaptcha: "CAPTCHA anhören",
refreshCaptcha: "CAPTCHA neu laden",
inputPlaceholder: "Code eingeben",
verifyButton: "Prüfen",
verificationSuccessful: "Erfolg!",
captchaRequired: "Bitte CAPTCHA eingeben",
captchaDoesNotMatch: "CAPTCHA stimmt nicht überein",
}}
/>
// Arabic (RTL)
<Captcha
rtl={true}
i18n={{
securityCheck: "فحص الأمان",
inputPlaceholder: "أدخل الرمز",
verifyButton: "تحقق",
refreshCaptcha: "رمز جديد",
}}
/>♿ Accessibility
ReCAPTZ is built with accessibility as a core feature, not an afterthought.
WCAG 2.1 AA Compliance
✅ Perceivable - Multiple ways to understand content (visual, audio, text)
✅ Operable - Full keyboard navigation, no time limits
✅ Understandable - Clear instructions, error messages, feedback
✅ Robust - Semantic HTML, ARIA labels, screen reader tested
Features
| Feature | Description | Support | | -------------------------- | ------------------------------------------ | --------------------- | | 🔊 Audio Feedback | Text-to-speech for visually impaired users | All text CAPTCHAs | | ⌨️ Keyboard Navigation | Complete keyboard control | All types | | 📱 Screen Readers | ARIA labels, semantic HTML | NVDA, JAWS, VoiceOver | | 🎨 High Contrast | Works with contrast themes | All themes | | 📐 Zoom Support | Maintains usability at 200% zoom | Responsive | | 👆 Touch Optimized | Large touch targets (44x44px min) | Mobile-first |
Keyboard Shortcuts
| Key | Action | Availability | | ----------------- | ------------------ | ------------ | | Space | Play audio CAPTCHA | Text types | | Enter | Validate input | All types | | Escape | Clear input | All types | | Tab | Navigate elements | All types |
Implementation
<Captcha
// Enable all accessibility features
enableAudio
autoFocus
// Provide clear labels
i18n={{
securityCheck: "Security Verification",
inputPlaceholder: "Enter the code you see or hear",
pressSpaceToHearCode: "Press Space to hear the code",
enterToValidate: "Press Enter to validate",
escToClear: "Press Escape to clear",
listenToCaptcha: "Listen to CAPTCHA (audio)",
refreshCaptcha: "Generate new CAPTCHA",
}}
// High contrast theme
darkMode
customStyles={{
border: "2px solid currentColor",
fontSize: "1.125rem",
}}
/>Screen Reader Example
<Captcha
type="numbers"
length={4}
enableAudio
i18n={{
securityCheck: "Please verify you are human",
inputPlaceholder: "Enter 4-digit code",
listenToCaptcha: "Click to hear the code",
}}
aria-label="Security verification CAPTCHA"
aria-describedby="captcha-instructions"
/>
## API Reference
| Property | Type | Default | Description |
| ---------------------- | ----------------------------------- | --------- | ---------------------------------- |
| `type` | `'numbers' \| 'letters' \| 'mixed'` | `'mixed'` | Type of CAPTCHA to generate |
| `length` | `number` | `6` | Length of CAPTCHA text |
| `onChange` | `(value: string) => void` | - | Callback when input changes |
| `onValidate` | `(isValid: boolean) => void` | - | Callback when validation occurs |
| `onRefresh` | `() => void` | - | Callback when CAPTCHA is refreshed |
| `onAudioPlay` | `() => void` | - | Callback when audio is played |
| `onError` | `(error: string) => void` | - | Callback when error occurs |
| `onFail` | `() => void` | - | Callback when validation fails |
| `onSuccess` | `() => void` | - | Callback when validation succeeds |
| `className` | `string` | `''` | Additional CSS classes |
| `customStyles` | `React.CSSProperties` | - | Custom inline styles |
| `inputButtonStyle` | `string` | `''` | Input button styles |
| `refreshable` | `boolean` | `true` | Whether CAPTCHA can be refreshed |
| `caseSensitive` | `boolean` | `false` | Case-sensitive validation |
| `customCharacters` | `string` | - | Custom character set |
| `validationRules` | `ValidationRules` | - | Custom validation rules |
| `darkMode` | `boolean` | `false` | Enable dark mode theme |
| `autoFocus` | `boolean` | `false` | Auto-focus the input field |
| `enableAudio` | `boolean` | `true` | Enable audio support |
| `disableSpaceToHear` | `boolean` | `false` | Disable space key audio feature |
| `showSuccessAnimation` | `boolean` | `false` | Show success animation |
| `showConfetti` | `boolean` | `false` | Show confetti on success |
| `confettiOptions` | `ConfettiOptions` | `{}` | Confetti configuration |
| `refreshInterval` | `number` | - | Auto-refresh interval in seconds |
| `maxAttempts` | `number` | - | Maximum validation attempts |
| `rtl` | `boolean` | `false` | Right-to-left layout |
| `i18n` | `I18nLabels` | - | Internationalization labels |
| `loadingComponent` | `React.ReactNode` | - | Custom loading component |
| `successComponent` | `React.ReactNode` | - | Custom success component |
| `errorComponent` | `React.ReactNode` | - | Custom error component |
| `theme` | `CaptchaTheme` | - | Custom theme configuration |
#### SliderCaptcha Configuration
| Property | Type | Default | Description |
| ------------------ | ---------- | ------- | ----------------------------------------- |
| `width` | `number` | `320` | Width of the puzzle canvas in pixels |
| `height` | `number` | `180` | Height of the puzzle canvas in pixels |
| `pieceSize` | `number` | `42` | Size of the puzzle piece in pixels |
| `tolerance` | `number` | `12` | Pixel tolerance for successful validation |
| `enableShadow` | `boolean` | `true` | Enable shadow effects on puzzle pieces |
| `backgroundImage` | `string` | - | Custom background image URL |
| `backgroundImages` | `string[]` | - | Array of custom background image URLs |
#### Component Props
| Property | Type | Default | Description |
| ---------------------- | ---------------------------------------------- | ------- | ------------------------------------- |
| `type` | `"slider"` | - | Must be set to "slider" |
| `sliderConfig` | `SliderCaptchaConfig` | `{}` | Configuration object for the slider |
| `darkMode` | `boolean` | `false` | Enable dark mode theme |
| `onValidate` | `(isValid: boolean, position: number) => void` | - | Callback when validation occurs |
| `onPositionChange` | `(position: number) => void` | - | Callback when slider position changes |
| `disabled` | `boolean` | `false` | Disable the slider interaction |
| `maxAttempts` | `number` | - | Maximum validation attempts |
| `onFail` | `() => void` | - | Callback when max attempts reached |
| `showSuccessAnimation` | `boolean` | `false` | Show success animation on validation |
| `showConfetti` | `boolean` | `false` | Show confetti effect on success |
| `confettiOptions` | `ConfettiOptions` | `{}` | Configuration for confetti animation |TypeScript Support
Full TypeScript definitions are included:
import type { CaptchaProps, ValidationRules, I18nLabels } from "recaptz";
const customValidation: ValidationRules = {
required: true,
minLength: 4,
customValidator: (value: string) => {
return value.length >= 4 || "Minimum 4 characters required";
},
};
const labels: I18nLabels = {
securityCheck: "Security Verification",
inputPlaceholder: "Enter code here",
verifyButton: "Verify Code",
};🌍 Browser Support
| Browser | Version | Status | | ------------- | --------------- | ------------------ | | Chrome | Last 2 versions | ✅ Fully Supported | | Firefox | Last 2 versions | ✅ Fully Supported | | Safari | Last 2 versions | ✅ Fully Supported | | Edge | Last 2 versions | ✅ Fully Supported | | Opera | Last 2 versions | ✅ Fully Supported | | Mobile Safari | iOS 12+ | ✅ Fully Supported | | Chrome Mobile | Android 8+ | ✅ Fully Supported |
Note: ReCAPTZ uses modern web APIs. For older browser support, consider using polyfills.
📚 Documentation
Complete API Reference
Visit our full documentation for detailed guides on:
🛡️ Security Best Practices
Recommended Configuration by Use Case
| Use Case | Type | Length | Config |
| ------------------ | ------------------ | ------ | -------------------- |
| Login Forms | numbers | 4 | Quick, user-friendly |
| Registration | mixed | 6 | Balanced security |
| Password Reset | letters | 5 | Medium security |
| Payment Forms | slider or math | - | High bot resistance |
| Comments | numbers | 4 | Low friction |
| Admin Panel | mixed | 8 | Maximum security |
| Public API | pattern | - | Bot prevention |
Security Recommendations
// ✅ GOOD - Login form
<Captcha
type="numbers"
length={4}
maxAttempts={5}
refreshInterval={60}
/>
// ✅ BETTER - High-security form
<Captcha
type="mixed"
length={8}
caseSensitive
maxAttempts={3}
validationRules={{
customValidator: (value) => {
// Add custom security checks
return /^(?=.*[A-Z])(?=.*[0-9])/.test(value)
|| "Must contain uppercase and number";
}
}}
/>
// ✅ BEST - Critical operations
<Captcha
type="slider"
maxAttempts={3}
onFail={() => {
// Lock account, send alert, etc.
lockAccountTemporarily();
}}
/>Performance Tips
- Use appropriate CAPTCHA type - Don't use
mixedwithlength={12}for simple forms - Implement rate limiting - Use
maxAttemptsto prevent brute force - Auto-refresh - Use
refreshIntervalto prevent stale CAPTCHAs - Lazy load - Load CAPTCHA component only when needed
- Monitor metrics - Track success rates and adjust difficulty
🤝 Contributing
We love contributions! ReCAPTZ is built by developers, for developers.
Ways to Contribute
Development Setup
# 1. Fork and clone
git clone https://github.com/ShejanMahamud/recaptz.git
cd recaptz
# 2. Install dependencies
pnpm install
# 3. Start dev server
pnpm dev
# 4. Run tests
pnpm test
# 5. Build library
pnpm buildContribution Guidelines
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please follow our Code of Conduct and Contributing Guidelines.
Development Commands
| Command | Description |
| ---------------- | ------------------------- |
| pnpm dev | Start development server |
| pnpm build | Build for production |
| pnpm test | Run test suite |
| pnpm lint | Lint code |
| pnpm format | Format code with Prettier |
| pnpm typecheck | Check TypeScript types |
💖 Support the Project
If ReCAPTZ helps your project, consider:
📄 License
MIT © Shejan Mahamud
Free to use in personal and commercial projects.
🙏 Acknowledgments
- Built with React & TypeScript
- Animations powered by Framer Motion
- Icons by Lucide
- Images from Pexels (Slider CAPTCHA)
📞 Community & Support
- 💬 GitHub Discussions - Ask questions, share ideas
- 🐛 Issue Tracker - Report bugs, request features
- 📧 Email - Direct support
- 🐦 Twitter - Follow for updates
Made with ❤️ by Shejan Mahamud
