npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-form-stepwise

v0.1.0

Published

A headless, TypeScript-first form stepwise library for React

Downloads

4

Readme

React Form Stepwise

A headless, TypeScript-first library for building multi-step forms in React.

You bring the UI. We handle the complexity.

npm version License: MIT


✨ Features

  • 🎯 Headless - No UI components, full styling control
  • 🔒 Type-safe - Built with TypeScript, full autocomplete support
  • Validation - Works with Zod, Yup, or custom validators
  • 💾 Persistence - Auto-save to localStorage (optional)
  • 🔀 Conditional steps - Show/hide steps based on form data
  • 📊 Progress tracking - Built-in progress calculation
  • 🪶 Lightweight - Small bundle size
  • Framework agnostic validation - Use any validation library
  • 🎨 Accessible - You control the markup and ARIA attributes

📦 Installation

npm install react-form-stepwise

Peer dependencies:

  • react ^18.0.0 or ^19.0.0

Note: zustand is included automatically as a dependency.


🚀 Quick Start

1. Define your Steps

import { createStepwiseStore } from 'react-form-stepwise';

type Steps = 'personal' | 'address' | 'confirmation';

const config = {
  steps: ['personal', 'address', 'confirmation'] as Steps[],
  persistKey: 'onboarding-form', // Optional: enables auto-save
};

const useFormSteps = createStepwiseStore(config);

2. Use in your component

import { useStepwise } from 'react-form-stepwise';

function MyForm() {
  const store = useFormSteps();
  const stepwise = useStepwise(store, config.steps);

  return (
    
      Step {stepwise.currentStepIndex + 1} of {stepwise.totalSteps}
      
      {/* Your step components */}
      {stepwise.currentStep === 'personal' && }
      {stepwise.currentStep === 'address' && }
      {stepwise.currentStep === 'confirmation' && }
      
      {/* Navigation */}
      
        Previous
      
      
        Next
      
    
  );
}

###3. Build Your Step Components

function PersonalStep({ stepwise }) {
  const data = stepwise.getStepData('personal') || {};
  const errors = stepwise.errors.personal || {};

  return (
      <input
        value={data.name || ''}
        onChange={(e) => stepwise.updateCurrentStepData({ name: e.target.value })}
      />
      {errors.name && {errors.name}}
    
  );
}

📖 Core Concepts

Type-Safe Steps

Define your steps with TypeScript for full autocomplete:

type OnboardingSteps = 'account' | 'profile' | 'preferences';

const useOnboarding = createStepwiseStore<OnboardingSteps>({
  steps: ['account', 'profile', 'preferences'],
});

// In your component
function MyComponent() {
  const store = useOnboarding();
  const stepwise = useStepwise(store, ['account', 'profile', 'preferences']);
  
  stepwise.goToStep('account');  // ✅ Autocomplete works
  stepwise.goToStep('invalid');  // ❌ TypeScript error
}

Validation

Use any validation library (zod, yup, custom functions):

Example with zod

import { z } from 'zod';

const personalSchema = z.object({
  name: z.string().min(1, 'Name is required'),
  email: z.string().email('Invalid email'),
});

const config = {
  steps: ['personal', 'address'],
  schemas: {
    personal: async (data) => {
      const result = personalSchema.safeParse(data);
      if (!result.success) {
        const errors = {};
        result.error.errors.forEach((err) => {
          if (err.path[0]) {
            errors[err.path[0]] = err.message;
          }
        });
        return errors;
      }
      return null;
    },
  },
};

Example with custom validation

const config = {
  steps: ['signup'],
  schemas: {
    signup: async (data) => {
      const errors = {};
      
      if (!data.email) {
        errors.email = 'Email is required';
      }
      
      // Async validation
      const isEmailTaken = await checkEmailAvailability(data.email);
      if (isEmailTaken) {
        errors.email = 'Email already registered';
      }
      
      return Object.keys(errors).length > 0 ? errors : null;
    },
  },
};

The stepwise automatically validates before advancing steps.

Persistence

Enable auto-save to local-storage:

const config = {
  steps: ['step1', 'step2'],
  persistKey: 'my-form', // Saves to localStorage as 'stepwise_my-form'
};

Users can close the browser and continue later. Clear persisted data with:

stepwise.clearPersistedData();

Conditional steps

Show/hide steps based on form data:

const config = {
  steps: [
    { id: 'account' },
    { 
      id: 'business',
      shouldShow: (formData) => formData.account?.type === 'business'
    },
    { id: 'payment' },
  ],
};

🎨 API Reference

createStepwiseStore(config)

Creates a Zustand store for your stepwise form.

Config options:

interface StepwiseConfig {
  // Required: list of step identifiers
  steps: TStepId[] | StepConfig[];
  
  // Optional: validation schemas per step
  schemas?: Partial<Record>;
  
  // Optional: localStorage key for persistence
  persistKey?: string;
  
  // Optional: initial form data
  initialData?: FormData;
  
  // Optional: callbacks
  onStepChange?: (from: TStepId | null, to: TStepId) => void;
  onComplete?: (data: FormData) => void;
  onError?: (error: Error) => void;
}

useStepwise(store, steps)

Hook that provides stepwise state and actions.

Returns:

{
  // Current state
  currentStep: string;
  currentStepIndex: number;
  totalSteps: number;
  isFirstStep: boolean;
  isLastStep: boolean;
  progress: number; // 0-100
  
  // Form data
  formData: Record;
  errors: Record>;
  
  // Navigation
  nextStep: () => Promise;
  previousStep: () => void;
  goToStep: (step: string) => Promise;
  canGoNext: boolean;
  canGoPrevious: boolean;
  
  // Data management
  updateStepData: (step: string, data: any) => void;
  updateCurrentStepData: (data: any) => void;
  resetForm: () => void;
  clearPersistedData: () => void;
  
  // Validation
  validateStep: (step: string) => Promise;
  validateAllSteps: () => Promise;
  setFieldError: (step: string, field: string, message: string) => void;
  clearErrors: (step?: string) => void;
  
  // Submission
  submitForm: (submitFn: (data) => Promise) => Promise;
  isSubmitting: boolean;
  
  // Utilities
  getStepData: (step: string) => T | undefined;
  hasStepData: (step: string) => boolean;
  visitedSteps: Set;
}

🎯 Use Cases

Perfect for:

  • ✅ Multi-step onboarding flows
  • ✅ Checkout processes
  • ✅ Survey forms
  • ✅ User registration forms
  • ✅ Configuration wizards
  • ✅ Application forms

Not ideal for:

  • ❌ Single-page forms (use React Hook Form directly)
  • ❌ Simple contact forms

📄 License

MIT © fhdzleon


🙏 Credits

Built with:

Inspired by the headless UI philosophy and the need for a simple, type-safe multi-step form solution.


🌟 Star us on GitHub!

If you find this library useful, please consider giving it a star ⭐

Built with ❤️ by skullDev81 ☠️ in spare time as part of continuous learning# react-form-stepwise