Skip to content

RegistryChain/plugin-wizard-form

Repository files navigation

@payloadcms/plugin-wizard-form

A multi-step wizard form plugin for Payload CMS that extends the official form builder with:

  • Multi-step wizard navigation - Break forms into logical steps with progress indicator
  • Conditional field display - Show/hide fields based on other field values
  • Calculated fields - Auto-compute values from formulas
  • Server-side validation - Formulas are re-computed on the server to prevent tampering
  • Tailwind CSS styling - Beautiful, customizable UI with CSS variables

Installation

npm install plugin-wizard-form
# or
pnpm add plugin-wizard-form
# or
yarn add plugin-wizard-form

Peer Dependencies

This plugin requires the following peer dependencies:

  • payload ^3.0.0
  • @payloadcms/plugin-form-builder ^3.0.0
  • react ^18.0.0 || ^19.0.0
  • react-dom ^18.0.0 || ^19.0.0

Quick Start

1. Add the Plugin to Payload Config

// payload.config.ts
import { buildConfig } from 'payload'
import { wizardFormPlugin } from '@payloadcms/plugin-wizard-form'

export default buildConfig({
  // ... your config
  plugins: [
    wizardFormPlugin({
      // Optional: pass form builder options
      formBuilderOptions: {
        redirectRelationships: ['pages'],
      },
    }),
  ],
})

2. Create a Wizard Form in Payload Admin

  1. Go to Forms collection in Payload admin
  2. Create a new form
  3. Check Enable Wizard Mode in the sidebar
  4. Add your form fields
  5. For each field, expand Wizard Settings to configure:
    • Step Number - Which wizard step this field belongs to (default: 1)
    • Step Label - Label shown in the step indicator (set on first field of each step)
    • Conditional Display - Show this field only when conditions are met
    • Calculated Field - Make this a read-only computed field

3. Render the Form in Next.js

// app/contact/page.tsx
import { WizardForm } from '@payloadcms/plugin-wizard-form/client'
import '@payloadcms/plugin-wizard-form/styles.css'

export default function ContactPage() {
  return (
    <div className="max-w-2xl mx-auto py-12">
      <WizardForm
        form="your-form-id"
        onSuccess={() => console.log('Form submitted!')}
        onError={(error) => console.error(error)}
      />
    </div>
  )
}

Or with a pre-fetched form:

import { getPayload } from 'payload'
import { WizardForm } from '@payloadcms/plugin-wizard-form/client'

export default async function ContactPage() {
  const payload = await getPayload({ config })
  const form = await payload.findByID({
    collection: 'forms',
    id: 'your-form-id',
  })

  return <WizardForm form={form} />
}

Configuration

Plugin Options

wizardFormPlugin({
  // Form builder options (passed through to @payloadcms/plugin-form-builder)
  formBuilderOptions: {
    redirectRelationships: ['pages'],
    // ... other form builder options
  },

  // Custom field blocks with wizard settings
  customBlocks: {
    // Your custom blocks will be extended with wizard settings
  },

  // Enable/disable server-side formula validation (default: true)
  enableServerValidation: true,

  // Additional form collection fields
  formOverrides: {
    fields: [
      // Additional fields for the Form collection
    ],
  },

  // Additional form submission fields
  formSubmissionOverrides: {
    fields: [
      // Additional fields for the Form Submission collection
    ],
  },
})

WizardForm Component Props

Prop Type Default Description
form string | WizardFormType required Form ID or populated form object
hiddenFields string[] [] Field names to hide
fieldComponents Record<string, FieldComponent> - Custom field components (override defaults)
classNames WizardClassNames - CSS class overrides for styling
nextLabel string "Next" Next button label
prevLabel string "Previous" Previous button label
submitLabel string "Submit" Submit button label
submitEndpoint string "/api/form-submissions" API endpoint for submissions
onSuccess () => void - Callback after successful submission
onError (error: Error) => void - Callback on submission error
onStepChange (step: number) => void - Callback when step changes

Wizard Settings

Step Configuration

Each form field has a Wizard Settings section with:

Setting Description
Step Number Which wizard step this field appears on (default: 1)
Step Label Label for the step indicator (set on first field of each step)

Conditional Display (showIf)

Show/hide fields based on other field values:

Option Description
Field Name of the field to check
Operator equals, notEquals, in, notIn, exists, notExists
Value Value to compare (comma-separated for in/notIn)

Example: Show "Company Name" only when "Account Type" equals "business":

  • Field: accountType
  • Operator: equals
  • Value: business

Calculated Fields

Create read-only computed fields:

Option Description
Formula Mathematical expression (e.g., quantity * price)
Output Key Key name for the computed result

Supported operations:

  • Basic arithmetic: +, -, *, /
  • Parentheses for grouping: (a + b) * c
  • Field references by name: quantity, price
  • Numeric literals: 100, 0.5

Custom Field Components

Override default field components with your own:

import { WizardForm } from '@payloadcms/plugin-wizard-form/client'

const CustomTextInput = ({ name, label, value, onChange, error, required }) => (
  <div>
    <label>{label} {required && '*'}</label>
    <input
      name={name}
      value={value || ''}
      onChange={(e) => onChange(e.target.value)}
    />
    {error && <span className="error">{error}</span>}
  </div>
)

export default function MyForm() {
  return (
    <WizardForm
      form="my-form-id"
      fieldComponents={{
        text: CustomTextInput,
        // Override other field types...
      }}
    />
  )
}

Styling

Using Tailwind CSS

Add the package to your Tailwind content configuration:

// tailwind.config.js
module.exports = {
  content: [
    // ... your content
    './node_modules/@payloadcms/plugin-wizard-form/dist/**/*.{js,mjs}',
  ],
}

CSS Variables

Customize colors using CSS variables:

:root {
  --wizard-primary: #3b82f6;
  --wizard-primary-hover: #2563eb;
  --wizard-secondary: #6b7280;
  --wizard-success: #22c55e;
  --wizard-error: #ef4444;
  --wizard-border: #e5e7eb;
  --wizard-background: #ffffff;
  --wizard-foreground: #111827;
  --wizard-muted: #f3f4f6;
  --wizard-muted-foreground: #6b7280;
}

/* Dark theme */
[data-theme="dark"] {
  --wizard-primary: #60a5fa;
  --wizard-background: #1f2937;
  /* ... */
}

Class Name Overrides

Use the classNames prop for fine-grained control:

<WizardForm
  form="my-form"
  classNames={{
    root: 'my-custom-form',
    content: 'px-6 py-4',
    stepIndicator: 'mb-8',
    field: 'mb-4',
    navigation: 'mt-8',
  }}
/>

useWizardForm Hook

For custom implementations, use the useWizardForm hook:

import { useWizardForm } from '@payloadcms/plugin-wizard-form/client'

function CustomWizardForm({ fields }) {
  const {
    currentStep,
    steps,
    isFirstStep,
    isLastStep,
    formValues,
    isCurrentStepValid,
    setValue,
    goToNext,
    goToPrevious,
  } = useWizardForm({
    fields,
    onStepChange: (step) => console.log('Step:', step),
  })

  return (
    <div>
      <h2>{currentStep?.label}</h2>
      {/* Render your custom form UI */}
    </div>
  )
}

Server-Side Security

All calculated fields are re-computed on the server before saving to prevent client-side tampering. The computed values are stored in a computed JSON field on the form submission.

To disable server-side validation (not recommended):

wizardFormPlugin({
  enableServerValidation: false,
})

Example: Multi-Step Registration Form

Step 1: Account Information

  • Email (required)
  • Account Type (select: personal/business)
  • Company Name (conditional: only when Account Type = business)

Step 2: Contact Details

  • Full Name (required)
  • Phone Number
  • Address

Step 3: Order Summary

  • Quantity (number)
  • Unit Price (number)
  • Total Price (calculated: quantity * unitPrice)

API Reference

Exports from @payloadcms/plugin-wizard-form

// Plugin
export { wizardFormPlugin } from '@payloadcms/plugin-wizard-form'

// Config
export { wizardFieldsConfig, getWizardFieldsConfig } from '@payloadcms/plugin-wizard-form'

// Server-side hook
export { recomputeFormulas } from '@payloadcms/plugin-wizard-form'

// Utilities
export {
  computeFormula,
  validateFormula,
  evaluateShowIf,
  buildSteps,
} from '@payloadcms/plugin-wizard-form'

Exports from @payloadcms/plugin-wizard-form/client

// Components
export { WizardForm, StepIndicator, StepNavigation } from '@payloadcms/plugin-wizard-form/client'

// Field components
export {
  Text, Textarea, Email, Number, Date,
  Select, Radio, Checkbox, Message,
  CalculatedField, FieldWrapper,
} from '@payloadcms/plugin-wizard-form/client'

// UI primitives
export { Button, Input, Label } from '@payloadcms/plugin-wizard-form/client'

// Hooks
export { useWizardForm } from '@payloadcms/plugin-wizard-form/client'

License

MIT License - see LICENSE for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published