GitHub

ContactForm

A reusable contact form block with built-in success state, validation support, and i18n capabilities.

Loading...

Basic Usage

import { ContactForm } from "@corew500/ui"

<ContactForm
  onFormSubmit={(data) => {
    console.log(data)
    // { firstName, lastName, email, company, subject, message }
  }}
/>

With Loading & Success States

const [loading, setLoading] = useState(false)
const [success, setSuccess] = useState(false)

<ContactForm
  loading={loading}
  success={success}
  onFormSubmit={async (data) => {
    setLoading(true)
    await submitForm(data)
    setLoading(false)
    setSuccess(true)
  }}
  successAction={
    <Button variant="outline" onClick={() => setSuccess(false)}>
      Send another message
    </Button>
  }
/>

Optional Fields

Enable additional fields as needed:

<ContactForm
  fields={{
    company: true,  // Shows company field
    subject: true,  // Shows subject field
  }}
/>

Custom Labels (i18n)

Localize all labels and placeholders:

<ContactForm
  title="Contactez-nous"
  description="Remplissez le formulaire ci-dessous."
  submitLabel="Envoyer"
  labels={{
    firstName: "Prénom",
    lastName: "Nom",
    email: "Courriel",
    company: "Entreprise",
    subject: "Sujet",
    message: "Message",
  }}
  placeholders={{
    firstName: "Jean",
    lastName: "Dupont",
    email: "jean@example.com",
    company: "Acme Inc.",
    subject: "Demande générale",
    message: "Votre message...",
  }}
/>

Validation Errors

Display validation errors for each field:

<ContactForm
  errors={{
    firstName: "First name is required",
    email: "Please enter a valid email address",
    message: "Message must be at least 10 characters",
  }}
/>

Custom Success Content

Customize the success state:

<ContactForm
  success={isSuccess}
  successTitle="Thank You!"
  successDescription="Your message has been received. We'll respond within 24 hours."
  successAction={<Button onClick={reset}>Send another</Button>}
/>

Props

PropTypeDefaultDescription
onFormSubmit(data: ContactFormData) => voidCalled when the form is submitted with form data
loadingenumfalseWhether the form is in a loading state
successenumfalseWhen true, shows success state instead of form
titlestringSend us a messageCustom title for the card header
descriptionstringFill out the form below and we'll get back to you as soon as possible.Custom description for the card header
successTitlestringMessage Sent!Title shown in success state
successDescriptionstringThank you for reaching out. We'll get back to you shortly.Description shown in success state
successSubDescriptionstringSecondary description shown in success state
successActionenumOptional action element for success state (e.g., "Send another message" button)
submitLabelstringSend MessageText for the submit button
loadingLabelstringSending...Text shown on submit button while loading
fields{ company?: boolean; subject?: boolean; }{}Which optional fields to show
placeholders{ firstName?: string; lastName?: string; email?: string; company?: string; subject?: string; message?: string; }{}Placeholder text for fields
labels{ firstName?: string; lastName?: string; email?: string; company?: string; subject?: string; message?: string; }{}Field labels (for i18n support)
errorsRecord<string, string>{}Validation error messages keyed by field name

ContactFormData Type

interface ContactFormData {
  firstName: string
  lastName: string
  email: string
  company: string | null
  subject: string | null
  message: string
}

LabelInputContainer Helper

The form also exports a LabelInputContainer component for consistent field layout:

import { LabelInputContainer } from "@corew500/ui"

<LabelInputContainer>
  <Label htmlFor="phone">Phone</Label>
  <Input id="phone" type="tel" />
</LabelInputContainer>

Accessibility

  • All inputs have associated labels via htmlFor/id
  • Error messages linked via aria-describedby
  • Invalid fields marked with aria-invalid="true"
  • Submit button disabled during loading
  • Success state uses role="status" for announcements