Inline Email Form
Installation
Add the following Soul components
The inline-email-form component uses the form-status and button components. Make sure you have added them to your project.
Install the following dependencies
npm install lucide-react @conform-to/react @conform-to/zod clsx
Copy and paste the following code into your project
sections/inline-email-form/index.tsx
'use client';import { getFormProps, getInputProps, SubmissionResult, useForm } from '@conform-to/react';import { parseWithZod } from '@conform-to/zod';import { clsx } from 'clsx';import { ArrowRight } from 'lucide-react';import { useActionState } from 'react';import { FormStatus } from '@/vibes/soul/form/form-status';import { Button } from '@/vibes/soul/primitives/button';import { schema } from './schema';type Action<State, Payload> = ( prevState: Awaited<State>, formData: Payload,) => State | Promise<State>;export interface InlineEmailFormProps { className?: string; placeholder?: string; submitLabel?: string; action: Action<{ lastResult: SubmissionResult | null; successMessage?: string }, FormData>;}/** * This component supports various CSS variables for theming. Here's a comprehensive list, along * with their default values: * * ```css * :root { * --inline-email-form-focus: hsl(var(--primary)); * --inline-email-form-background: hsl(var(--background)); * --inline-email-form-placeholder: hsl(var(--contrast-500)); * --inline-email-form-text: hsl(var(--foreground)); * --inline-email-form-border: hsl(var(--black)); * --inline-email-form-error: hsl(var(--error)); * } * ``` */export function InlineEmailForm({ className, action, submitLabel = 'Submit', placeholder = 'Enter your email',}: InlineEmailFormProps) { const [{ lastResult, successMessage }, formAction, isPending] = useActionState(action, { lastResult: null, }); const [form, fields] = useForm({ lastResult, onValidate({ formData }) { return parseWithZod(formData, { schema }); }, shouldValidate: 'onSubmit', shouldRevalidate: 'onInput', }); const { errors = [] } = fields.email; return ( <form {...getFormProps(form)} action={formAction} className={clsx('space-y-2', className)}> <div className={clsx( 'relative rounded-xl border bg-[var(--inline-email-form-background,hsl(var(--background)))] text-base transition-colors duration-200 focus-within:border-[var(--inline-email-form-focus,hsl(var(--primary)))] focus:outline-none', errors.length ? 'border-[var(--inline-email-form-error,hsl(var(--error)))]' : 'border-[var(--inline-email-form-border,hsl(var(--black)))]', )} > <input {...getInputProps(fields.email, { type: 'email' })} className="h-14 w-full bg-transparent pl-5 pr-16 text-[var(--inline-email-form-text,hsl(var(--foreground)))] placeholder-[var(--inline-email-form-placeholder,hsl(var(--contrast-500)))] placeholder:font-normal focus:outline-none" data-1p-ignore key={fields.email.id} placeholder={placeholder} /> <div className="absolute right-0 top-1/2 -translate-y-1/2 pr-2"> <Button aria-label={submitLabel} loading={isPending} shape="circle" size="small" type="submit" variant="secondary" > <ArrowRight size={20} strokeWidth={1.5} /> </Button> </div> </div> <div className="mt-2"> {errors.map((error, index) => ( <FormStatus key={index} type="error"> {error} </FormStatus> ))} {form.status === 'success' && successMessage != null && ( <FormStatus>{successMessage}</FormStatus> )} </div> </form> );}
sections/inline-email-form/schema.ts
import { z } from 'zod';export const schema = z.object({ email: z.string().email(),});
Usage
import { InlineEmailForm } from '@/vibes/soul/sections/inline-email-form';import { parseWithZod } from '@conform-to/zod';import { z } from 'zod';function Usage() { return ( <InlineEmailForm action={async (lastResult, formData) => { 'use server'; const schema = z.object({ email: z.string().email(), }); const submission = parseWithZod(formData, { schema }); if (submission.status !== 'success') { return { lastResult: submission.reply({ formErrors: ['Boom!'] }) }; } return { lastResult: submission.reply(), successMessage: 'Subscribed!' }; }} /> );}
API Reference
InlineEmailFormProps
Prop | Type | Default |
---|---|---|
className | string | |
placeholder | string | |
submitLabel | string | |
action | Action<{ lastResult: SubmissionResult | null; successMessage?: string }, FormData> |
CSS Variables
This component supports various CSS variables for theming. Here's a comprehensive list.
:root { --inline-email-form-focus: hsl(var(--primary)); --inline-email-form-background: hsl(var(--background)); --inline-email-form-placeholder: hsl(var(--contrast-500)); --inline-email-form-text: hsl(var(--foreground)); --inline-email-form-border: hsl(var(--black)); --inline-email-form-error: hsl(var(--error));}