@vulform/react
Version:
React components for VulForm contact form management
565 lines (461 loc) • 14.7 kB
Markdown
# @vulform/react
React components for VulForm contact form management.
## Installation
```bash
npm install @vulform/react
# or
yarn add @vulform/react
# or
bun add @vulform/react
```
## Quick Start
```jsx
import { VulForm } from '@vulform/react';
function ContactPage() {
return (
<VulForm
templateId='your-template-id'
apiKey='vf_your_api_key_here'
onSuccess={response => console.log('Form submitted!', response)}
onError={error => console.error('Submission failed:', error)}
/>
);
}
```
## URL Configuration
VulForm React supports flexible URL configuration for different deployment scenarios:
### 1. **Using VulForm SaaS (Default)**
No configuration needed - automatically uses `https://api.vulform.dev`:
```jsx
<VulForm
templateId='your-template-id'
apiKey='vf_your_api_key_here'
// apiUrl is auto-detected
/>
```
### 2. **Self-Hosted VulForm**
Use relative URLs for same-domain deployment:
```jsx
<VulForm templateId='your-template-id' apiKey='vf_your_api_key_here' apiUrl='/api/v1' />
```
### 3. **Custom Domain**
Point to your custom VulForm instance:
```jsx
<VulForm
templateId='your-template-id'
apiKey='vf_your_api_key_here'
apiUrl='https://forms.mycompany.com/api'
/>
```
### 4. **Environment Variables**
Set up environment variables for automatic configuration:
```bash
# Next.js
NEXT_PUBLIC_VULFORM_API_KEY=vf_your_key_here
NEXT_PUBLIC_VULFORM_BASE_URL=https://forms.mycompany.com/api
# Create React App
REACT_APP_VULFORM_API_KEY=vf_your_key_here
REACT_APP_VULFORM_BASE_URL=https://forms.mycompany.com/api
```
Then use without props:
```jsx
<VulForm
templateId='your-template-id'
// apiKey and apiUrl are read from environment variables
/>
```
### URL Resolution Priority
VulForm resolves the API URL in this order:
1. **`apiUrl` prop** (highest priority)
2. **Environment variables**: `NEXT_PUBLIC_VULFORM_BASE_URL` or `REACT_APP_VULFORM_BASE_URL`
3. **Auto-detection**:
- Development: `http://localhost:3000/api/v1`
- Production: `https://api.vulform.dev` (SaaS)
## Props
| Prop | Type | Default | Description |
| -------------------- | -------------------------------------- | ----------------------------------------- | ----------------------------------------- |
| `templateId` | `string` | **Required** | Your VulForm template ID |
| `apiKey` | `string` | `process.env.NEXT_PUBLIC_VULFORM_API_KEY` | Your VulForm API key |
| `apiUrl` | `string` | Auto-detected | VulForm API URL |
| `theme` | `'auto' \| 'light' \| 'dark'` | `'auto'` | Form theme |
| `className` | `string` | `''` | CSS class for the form container |
| `style` | `React.CSSProperties` | `{}` | Inline styles for the form container |
| `prefill` | `object` | `{}` | Pre-fill form fields |
| `onSuccess` | `(response: any) => void` | `undefined` | Success callback |
| `onError` | `(error: VulFormError) => void` | `undefined` | Error callback |
| `onValidationError` | `(errors: ValidationErrors) => void` | `undefined` | Validation error callback |
| `onFieldChange` | `(field: string, value: any) => void` | `undefined` | Field change callback |
| `enableAnalytics` | `boolean` | `true` | Enable form analytics |
| `spamProtection` | `boolean` | `true` | Enable spam protection |
| `loadingState` | `'default' \| 'skeleton' \| 'spinner'` | `'default'` | Loading state style |
| `resetOnSuccess` | `boolean` | `true` | Reset form after successful submission |
| `showSuccessMessage` | `boolean` | `true` | Show success message after submission |
| `autoRedirect` | `boolean` | `false` | Auto-redirect after successful submission |
## Advanced Usage
### Custom Styling
```jsx
<VulForm
templateId='your-template-id'
className='my-custom-form'
style={{
maxWidth: '600px',
margin: '0 auto',
padding: '2rem',
backgroundColor: '#f9fafb',
borderRadius: '0.5rem',
}}
/>
```
### Form Events
```jsx
<VulForm
templateId='your-template-id'
onSuccess={response => {
console.log('Form submitted successfully:', response);
// Redirect to thank you page
window.location.href = '/thank-you';
}}
onError={error => {
console.error('Form submission failed:', error);
// Show custom error message
alert(`Error: ${error.message}`);
}}
onFieldChange={(fieldName, value) => {
console.log(`Field ${fieldName} changed to:`, value);
// Custom field validation or side effects
}}
/>
```
### Pre-filling Fields
```jsx
<VulForm
templateId='your-template-id'
prefill={{
name: 'John Doe',
email: 'john@example.com',
company: 'Acme Corp',
}}
/>
```
### Using the Hook Directly
For more control, use the `useVulForm` hook:
```jsx
import { useVulForm } from '@vulform/react';
function CustomForm() {
const {
template,
loading,
error,
submitting,
submitted,
formData,
validationErrors,
updateField,
submitForm,
resetForm,
} = useVulForm({
templateId: 'your-template-id',
apiKey: 'vf_your_api_key_here',
apiUrl: 'https://forms.mycompany.com/api', // Optional
onSuccess: response => console.log('Success!', response),
onError: error => console.error('Error:', error),
});
if (loading) return <div>Loading form...</div>;
if (error) return <div>Error: {error.message}</div>;
if (submitted) return <div>Thank you for your submission!</div>;
return (
<form
onSubmit={e => {
e.preventDefault();
submitForm();
}}
>
{template?.fields.map(field => (
<div key={field.id}>
<label>{field.label}</label>
<input
type={field.type}
value={formData[field.name] || ''}
onChange={e => updateField(field.name, e.target.value)}
disabled={submitting}
/>
{validationErrors[field.name] && (
<span className='error'>{validationErrors[field.name]}</span>
)}
</div>
))}
<button type='submit' disabled={submitting}>
{submitting ? 'Submitting...' : 'Submit'}
</button>
</form>
);
}
```
## Deployment Examples
### Next.js App Router
```jsx
// app/contact/page.tsx
import { VulForm } from '@vulform/react';
export default function ContactPage() {
return (
<div className='container mx-auto py-8'>
<h1 className='text-3xl font-bold mb-8'>Contact Us</h1>
<VulForm
templateId={process.env.NEXT_PUBLIC_VULFORM_TEMPLATE_ID}
// API key and URL are read from environment variables
onSuccess={() => {
// Handle success (e.g., show thank you message, redirect)
}}
/>
</div>
);
}
```
### Create React App
```jsx
// src/components/ContactForm.jsx
import { VulForm } from '@vulform/react';
function ContactForm() {
return (
<VulForm
templateId={process.env.REACT_APP_VULFORM_TEMPLATE_ID}
// Configuration is read from REACT_APP_* environment variables
className='max-w-md mx-auto'
onSuccess={response => {
console.log('Form submitted:', response);
}}
/>
);
}
export default ContactForm;
```
### Self-Hosted Setup
```jsx
// For self-hosted VulForm instance
<VulForm
templateId='your-template-id'
apiKey='vf_your_api_key_here'
apiUrl='/api/v1' // Relative URL for same-domain deployment
/>
```
## TypeScript Support
Full TypeScript support with comprehensive type definitions:
```tsx
import { VulForm, VulFormProps, useVulForm } from '@vulform/react';
import type { SubmissionResponse, VulFormError, ValidationErrors } from '@vulform/core';
const formProps: VulFormProps = {
templateId: 'your-template-id',
apiKey: 'vf_your_key_here',
onSuccess: (response: SubmissionResponse) => {
console.log('Success:', response);
},
onError: (error: VulFormError) => {
console.error('Error:', error);
},
onValidationError: (errors: ValidationErrors) => {
console.log('Validation errors:', errors);
},
};
export default function TypedForm() {
return <VulForm {...formProps} />;
}
```
## Components
### VulForm
The main component that renders a complete form based on a template.
```tsx
<VulForm
templateId='contact-form'
apiKey='vf_abc123' // Optional if set in env
apiUrl='/api/v1' // Optional, defaults to /api/v1
// Styling
theme='auto' // 'auto' | 'light' | 'dark' | custom theme object
className='my-form'
// Data
prefill={{ name: 'John Doe' }}
// Event handlers
onSuccess={response => console.log('Success!', response)}
onError={error => console.error('Error:', error)}
onValidationError={errors => console.log('Validation errors:', errors)}
onFieldChange={(fieldName, value) => console.log('Field changed:', fieldName, value)}
// Features
enableAnalytics={true}
spamProtection={true}
resetOnSuccess={true}
showSuccessMessage={true}
/>
```
### Individual Components
```tsx
import { FormField, FormLoader, FormSuccess, FormErrorComponent } from '@vulform/react';
// Custom loading state
<FormLoader loadingState="custom" />
// Success message
<FormSuccess
message="Thank you!"
onReset={() => resetForm()}
/>
// Error display
<FormErrorComponent
error={{ code: 'NETWORK_ERROR', message: 'Connection failed' }}
onRetry={() => retrySubmission()}
/>
```
## Hooks
### useVulForm
Custom hook for building your own form components:
```tsx
import { useVulForm } from '@vulform/react';
function CustomForm() {
const {
template,
loading,
error,
submitting,
formData,
validationErrors,
updateField,
submitForm,
resetForm,
} = useVulForm({
templateId: 'contact-form',
onSuccess: response => console.log('Success!'),
onError: error => console.error('Error:', error),
});
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<form
onSubmit={e => {
e.preventDefault();
submitForm();
}}
>
{template?.fields.map(field => (
<input
key={field.id}
type={field.type}
value={formData[field.name] || ''}
onChange={e => updateField(field.name, e.target.value)}
/>
))}
<button type='submit' disabled={submitting}>
{submitting ? 'Sending...' : 'Submit'}
</button>
</form>
);
}
```
### useFieldValidation
Real-time field validation:
```tsx
import { useFieldValidation } from '@vulform/react';
function EmailField({ field, apiClient }) {
const [value, setValue] = useState('');
const { error, isValidating } = useFieldValidation({
field,
value,
apiClient,
debounceMs: 300,
});
return (
<div>
<input
value={value}
onChange={e => setValue(e.target.value)}
style={{ borderColor: error ? 'red' : undefined }}
/>
{isValidating && <span>Validating...</span>}
{error && <span style={{ color: 'red' }}>{error}</span>}
</div>
);
}
```
## Styling
### CSS Variables
VulForm components use CSS variables that you can customize:
```css
.vulform-container {
--vulform-primary: #3b82f6;
--vulform-secondary: #1e40af;
--vulform-background: #ffffff;
--vulform-text: #374151;
--vulform-border: #d1d5db;
--vulform-border-radius: 0.5rem;
--vulform-font-family: 'Inter', sans-serif;
--vulform-font-size: 1rem;
--vulform-spacing: 1rem;
}
```
### Custom Themes
```tsx
const customTheme = {
primaryColor: '#10b981',
secondaryColor: '#059669',
backgroundColor: '#f9fafb',
textColor: '#111827',
borderColor: '#d1d5db',
borderRadius: '0.75rem',
fontFamily: 'system-ui',
fontSize: '1rem',
spacing: '1.5rem',
};
<VulForm templateId='contact-form' theme={customTheme} />;
```
### Tailwind CSS
VulForm works great with Tailwind CSS. Components include sensible default classes:
```tsx
<VulForm
templateId='contact-form'
className='max-w-2xl mx-auto p-6 bg-white rounded-lg shadow-lg'
/>
```
## Form Templates
Create form templates in the VulForm dashboard, then reference them by ID:
```tsx
// Template ID from dashboard
<VulForm templateId='cmc2o5rpm0007ju0d4et2g97d' />
```
Templates include:
- Field definitions (text, email, textarea, select, etc.)
- Validation rules
- Layout settings (vertical, horizontal, grid)
- Styling and themes
- Success/error messages
## Error Handling
```tsx
import { VulFormError } from '@vulform/react';
<VulForm
templateId='contact-form'
onError={(error: VulFormError) => {
switch (error.code) {
case 'MISSING_API_KEY':
console.error('API key not configured');
break;
case 'TEMPLATE_NOT_FOUND':
console.error('Form template not found');
break;
case 'RATE_LIMIT_EXCEEDED':
console.error('Too many requests');
break;
case 'NETWORK_ERROR':
console.error('Network connection failed');
break;
default:
console.error('Unknown error:', error.message);
}
}}
/>;
```
## 📦 CDN Usage
**Via unpkg.com:**
```html
<script src="https://unpkg.com/@vulform/react@latest/dist/index.js"></script>
```
**Via jsDelivr:**
```html
<script src="https://cdn.jsdelivr.net/npm/@vulform/react@latest/dist/index.js"></script>
```
> **Note:** For React applications, we recommend using the npm package for better tree-shaking and TypeScript support.
## License
MIT