pgForm/Getting started
Getting started~10 min
Getting started
A working two-field form in four steps. Declare your fields, write your input components, mount the store with usePgForm, and render with GeneratePgForm. Nothing more, nothing magic.
1. Declare your fields
Each entry in pgf.formData(...) describes a single field — its type, default value, validators, dynamic props, and free-form metadata you read from your input components.
TSXfields.ts
import { pgf } from '@westopp/pgform' export const fields = pgf.formData({ fullName: { type: 'text', defaultValue: '', required: { value: true, message: 'Your name is required' }, metadata: { label: 'Full name', placeholder: 'Ada Lovelace' }, }, email: { type: 'email', defaultValue: '', required: { value: true, message: 'An email is required' }, metadata: { label: 'Email', placeholder: 'ada@example.com' }, }, })
2. Write your input components
pgForm is BYOC (bring your own components). For each field type you use, you supply a component that receives standardized props — fieldKey, value, onChange, onBlur, onFocus, fieldApi, cn, metadata.
TSXTextInput.tsx
import type { PgFormTextFieldProps } from '@westopp/pgform' export function TextInput({ fieldKey, value, onChange, onBlur, onFocus, fieldApi, cn, metadata }: PgFormTextFieldProps) { return ( <label> <span>{metadata?.label ?? fieldKey}</span> <input type="text" name={fieldKey} value={value ?? ''} placeholder={metadata?.placeholder} onChange={(e) => onChange(e.target.value)} onBlur={onBlur} onFocus={onFocus} disabled={fieldApi.isDisabled} readOnly={fieldApi.isReadonly} className={cn('input')} /> {fieldApi.firstError && <p>{fieldApi.firstError.message}</p>} </label> ) }
3. Mount the form with usePgForm
usePgForm mounts the store entry and returns a typed formApi plus the generateFormProps you pass to the renderer.
TSXMyForm.tsx
import { GeneratePgForm, usePgForm, type PgFormFieldComponents } from '@westopp/pgform' import { fields } from './fields' import { TextInput, EmailInput } from './inputs' const components: PgFormFieldComponents<typeof fields> = { text: TextInput, email: EmailInput } export const MyForm = () => { const form = usePgForm(fields, { validationMode: 'onBlur', revalidationMode: 'onChange', onSubmit: (values) => console.log(values), }) return ( <> <GeneratePgForm generateFormProps={form.generateFormProps} components={components} /> <button type="button" onClick={() => form.formApi.submit()}>Submit</button> </> ) }
Here it is mounted live. Fill in the fields and submit to see the values panel update.
Submitted values
// submit the form to see values