@tempered/hydrogen-forms
v0.0.0
Published
Contact form components for Shopify Hydrogen storefronts
Maintainers
Readme
@tempered/hydrogen-forms
Contact form components for Shopify Hydrogen storefronts.
Installation
npm install @tempered/hydrogen-forms
# or
pnpm add @tempered/hydrogen-formsQuick Start
1. Add the Provider
Wrap your Hydrogen app with the FormProvider:
// app/root.tsx
import { FormProvider } from '@tempered/hydrogen-forms';
export default function App() {
return (
<FormProvider
config={{
apiUrl: 'https://formbridge.temperedtools.xyz',
shopDomain: 'your-store.myshopify.com',
}}
>
<Outlet />
</FormProvider>
);
}2. Add a Contact Form
// app/routes/contact.tsx
import { ContactForm } from '@tempered/hydrogen-forms';
export default function ContactPage() {
return (
<div>
<h1>Contact Us</h1>
<ContactForm
formId="form_abc123"
showSubject
onSuccess={(response) => console.log('Submitted:', response.submissionId)}
/>
</div>
);
}3. Add Newsletter Signup
// app/components/Footer.tsx
import { NewsletterSignup } from '@tempered/hydrogen-forms';
export function Footer() {
return (
<footer>
<NewsletterSignup
formId="form_newsletter"
inline
placeholder="[email protected]"
buttonText="Subscribe"
/>
</footer>
);
}Components
FormProvider
Context provider that must wrap your app.
<FormProvider
config={{
apiUrl: 'https://formbridge.temperedtools.xyz',
shopDomain: 'your-store.myshopify.com',
apiKey: 'optional_api_key', // For authenticated requests
}}
>
{children}
</FormProvider>ContactForm
Pre-built contact form with name, email, subject, and message fields.
<ContactForm
formId="form_id"
showSubject={true}
onSuccess={(response) => {}}
onError={(error) => {}}
classNames={{
form: 'my-form',
field: 'form-field',
input: 'form-input',
button: 'submit-btn',
}}
labels={{
name: 'Your Name',
email: 'Email Address',
submit: 'Send Message',
}}
/>NewsletterSignup
Minimal newsletter signup form.
<NewsletterSignup
formId="form_id"
inline={true}
placeholder="Enter your email"
buttonText="Subscribe"
successMessage="Thanks for subscribing!"
/>CustomForm
Dynamic form that loads fields from the FormBridge backend.
<CustomForm
formId="form_id"
onSuccess={(response) => {}}
submitText="Submit"
loadingText="Submitting..."
renderLoading={() => <div>Loading form...</div>}
/>FormField
Individual form field component.
<FormField
name="email"
label="Email Address"
type="email"
value={value}
onChange={handleChange}
onBlur={handleBlur}
required
error={error}
touched={touched}
/>Hooks
useForm
Core form state management.
const form = useForm({
initialValues: { name: '', email: '' },
fields: [
{ id: '1', name: 'name', label: 'Name', type: 'text', required: true, sortOrder: 0 },
{ id: '2', name: 'email', label: 'Email', type: 'email', required: true, sortOrder: 1 },
],
});
// Use form state
form.getValue('email');
form.setValue('email', '[email protected]');
form.getError('email');
form.validate();
form.getFieldProps('email'); // { name, value, onChange, onBlur }useSubmit
Form submission handler.
const { submit, isSubmitting, error, response } = useSubmit({
formId: 'form_id',
onSuccess: (response) => console.log('Success:', response),
onError: (error) => console.error('Error:', error),
});
await submit({ name: 'John', email: '[email protected]' });useValidation
Form validation utilities.
const { validate, validateSingle, isRequired } = useValidation({
fields: formConfig.fields,
});
const result = validate(formValues);
// { isValid: boolean, errors: { fieldName: 'error message' } }useFetchFormConfig
Fetch form configuration from the API.
const { config, isLoading, error, refetch } = useFetchFormConfig({
formId: 'form_id',
});Server-Side Utilities
For SSR in Hydrogen:
// app/routes/contact.tsx
import { fetchFormConfig, submitForm, createFormBridgeConfig } from '@tempered/hydrogen-forms/server';
export async function loader({ context }) {
const config = await fetchFormConfig({
formId: 'form_id',
apiUrl: 'https://formbridge.temperedtools.xyz',
});
return { formConfig: config };
}
export async function action({ request, context }) {
const formData = await request.formData();
const result = await submitForm({
formId: 'form_id',
data: Object.fromEntries(formData),
config: createFormBridgeConfig({
shopDomain: context.env.PUBLIC_STORE_DOMAIN,
}),
});
return result;
}Styling
All components accept className and classNames props for styling:
<ContactForm
formId="form_id"
classNames={{
form: 'contact-form',
field: 'form-group',
input: 'form-control',
label: 'form-label',
error: 'invalid-feedback',
button: 'btn btn-primary',
successMessage: 'alert alert-success',
errorMessage: 'alert alert-danger',
}}
/>Spam Protection
FormBridge includes built-in spam protection:
- Honeypot fields - Hidden fields that bots fill out
- Timing analysis - Detects submissions that are too fast
- Turnstile verification - Optional Cloudflare Turnstile support
The npm package handles honeypot and timing automatically. No configuration required.
TypeScript
Full TypeScript support with exported types:
import type {
FormBridgeConfig,
FormConfig,
FormField,
FieldType,
SubmissionResponse,
ContactFormProps,
UseFormReturn,
} from '@tempered/hydrogen-forms';Accessibility
All components are WCAG 2.2 AA compliant:
- Proper label associations
- Error messages with
aria-live - Keyboard navigation support
- Focus management on submission
- Required field indicators
Bundle Size
< 30kb gzipped. Tree-shakeable exports.
License
MIT
