npm package: @naktor/contact-form
Description: Reusable contact form with Turnstile CAPTCHA, Honeypot protection, and Zod validation
Author: Naktor
Latest version: 1.2.0

# @naktor/contact-form

A reusable, customizable contact form component with built-in Cloudflare Turnstile CAPTCHA, honeypot protection, and Zod validation.

## Features

- **Cloudflare Turnstile** - Invisible CAPTCHA protection
- **Honeypot field** - Additional bot protection
- **Zod validation** - Type-safe form validation
- **i18n support** - Built-in Spanish and English error messages
- **Render props** - Fully customizable UI
- **TypeScript** - Full type definitions included

## Installation

```bash
npm install @naktor/contact-form
# or
pnpm add @naktor/contact-form
# or
yarn add @naktor/contact-form
```

## Peer Dependencies

Make sure you have these installed:

```bash
npm install react react-dom zod
```

## Usage

### Client-side (React Component)

```tsx
import { ContactForm, type ContactFormTranslations } from "@naktor/contact-form";
import { errorMessagesEN } from "@naktor/contact-form/schemas";

const translations: ContactFormTranslations = {
  labels: {
    name: "Name",
    company: "Company",
    email: "Email",
    message: "Message",
  },
  placeholders: {
    name: "Your name",
    email: "your@email.com",
    message: "Tell us about your project...",
  },
  submitButton: "Send Message",
  submittingButton: "Sending...",
  successTitle: "Message Sent!",
  successMessage: "We'll get back to you soon.",
  errorMessages: errorMessagesEN,
  apiErrors: {
    rateLimited: "Too many attempts. Please wait.",
    verificationFailed: "Verification failed. Please reload.",
    serverError: "Server error. Please try again.",
    networkError: "Connection error. Check your internet.",
  },
};

export default function ContactPage() {
  return (
    <ContactForm
      translations={translations}
      turnstileSiteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY || ""}
      apiEndpoint="/api/contact"
      className="space-y-4"
      onSuccess={() => console.log("Form submitted!")}
    />
  );
}
```

### Server-side (API Route)

```ts
// app/api/contact/route.ts (Next.js App Router)
import { verifyTurnstileToken, isHoneypotFilled } from "@naktor/contact-form/server";
import { contactSchemaServer } from "@naktor/contact-form/schemas";

export async function POST(request: Request) {
  const body = await request.json();

  // Check honeypot
  if (isHoneypotFilled(body.website)) {
    return Response.json({ success: true }); // Silent success for bots
  }

  // Verify Turnstile token
  const turnstileResult = await verifyTurnstileToken(body.turnstileToken);
  if (!turnstileResult.success) {
    return Response.json({ error: "Verification failed" }, { status: 403 });
  }

  // Validate form data
  const validationResult = contactSchemaServer.safeParse(body);
  if (!validationResult.success) {
    return Response.json({ error: "Invalid data" }, { status: 400 });
  }

  // Process the form (send email, save to DB, etc.)
  const { name, email, company, message } = validationResult.data;

  // ... your logic here

  return Response.json({ success: true });
}
```

## Customizing the UI

Use render props to fully customize the form appearance:

```tsx
<ContactForm
  translations={translations}
  turnstileSiteKey="..."
  renderInput={({ id, name, type, label, placeholder, value, onChange, error }) => (
    <div className="my-custom-input">
      <label htmlFor={id}>{label}</label>
      <input
        id={id}
        name={name}
        type={type}
        placeholder={placeholder}
        value={value}
        onChange={onChange}
      />
      {error && <span className="error">{error}</span>}
    </div>
  )}
  renderButton={({ type, disabled, isSubmitting, text }) => (
    <button type={type} disabled={disabled} className="my-button">
      {text}
    </button>
  )}
  renderSuccess={({ title, message }) => (
    <div className="success-message">
      <h3>{title}</h3>
      <p>{message}</p>
    </div>
  )}
/>
```

## Environment Variables

```env
# Client-side (public)
NEXT_PUBLIC_TURNSTILE_SITE_KEY=your_site_key

# Server-side (secret)
TURNSTILE_SECRET_KEY=your_secret_key
```

## API Reference

### Exports

#### `@naktor/contact-form` (client)
- `ContactForm` - Main form component
- `TurnstileWidget` - Standalone Turnstile widget
- `resetTurnstile` - Function to reset the widget

#### `@naktor/contact-form/server`
- `verifyTurnstileToken` - Verify Turnstile token on server
- `isHoneypotFilled` - Check if honeypot field was filled

#### `@naktor/contact-form/schemas`
- `createContactSchema` - Create a Zod schema with custom messages
- `contactSchemaServer` - Pre-configured schema for server
- `errorMessagesES` - Spanish error messages
- `errorMessagesEN` - English error messages

## License

MIT