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-headless-stepper

v1.0.0

Published

A flexible, headless, and composable multi-step component library for React.

Readme

react-headless-stepper

NPM version License

A flexible, headless, and composable multi-step component library for React that gives you complete control over your UI.

Features

  • Headless & Unstyled: Our library is unstyled by design. We don't manage your component's appearance; we just provide the functional tools you need to implement the logic exactly how you want.

  • Full Control: Exposes the stepper's state and actions through a consumer component and a hook, allowing for maximum flexibility.

  • State Management Included: Handles all the step progression logic internally.

  • Composable: Built with a composable API that is intuitive and easy to use.

Installation

npm install react-headless-stepper
# or
yarn add react-headless-stepper

Basic Usage

Here's a simple example to get you started.

import React from 'react';
import { Stepper, useStepper } from 'react-headless-stepper';

function MyStepper() {
  return (
    <Stepper.Root>
      <Stepper.Consumer>
        {(context) => (
          // Consumer examples bellow
        )}
      </Stepper.Consumer>

      <Stepper.Content>
        <Stepper.Item>1</Stepper.Item>
        <Stepper.Item>2</Stepper.Item>
      </Stepper.Content>

      <Stepper.Prev>
        <button type="button">Prev</button>
      </Stepper.Prev>

      <Stepper.Next>
        <button type="button">Next</button>
      </Stepper.Next>

      <Stepper.Submit>
        <button type="submit">Submit</button>
      </Stepper.Submit>
    </Stepper.Root>
  );
}

Manipulating the Stepper State

You can control the stepper's state and navigation from your components in two ways: using the Stepper.Consumer component or the useStepper hook.

Both Stepper.Consumer and useStepper give you access to the exact same set of following tools:

| Name | Type | Description | | ----------------- | ------------------- | ----------------------------------------------------------- | | nextStep() | function | Advances to the next step. | | prevStep() | function | Returns to the previous step. | | goTo() | (index: number) | Navigates directly to a specific step by its index. | | defineTotalSteps() | (count: number) | Allows you to manually set the total number of steps. | | currentStep | number | The index of the current step (starting from 1). | | totalSteps | number | The total number of steps. | | isLastStep | boolean | true if the current step is the last one. | | isFirstStep | boolean | true if the current step is the first one. |


Usage Examples

1. Using Stepper.Consumer

This component uses the Render Prop pattern. It expects a function as its children prop, which is then called with an object containing the stepper's state and actions as its arguments.

import { Stepper } from 'react-headless-stepper';

const MyStepper = () => (
  <Stepper.Root>
    <Stepper.Consumer>
      {({ currentStep, totalSteps }) => (
        <div>
          <p>Step {currentStep} of {totalSteps}</p>
        </div>
      )}
    </Stepper.Consumer>
  </Stepper.Root>
);

2. Using the useStepper Hook

import { Stepper, useStepper } from 'react-headless-stepper';

const MyStepper = () => (
  <Stepper.Root>
    <Stepper.Content>
      <Stepper.Item>Step 1</Stepper.Item>
      <StepTwo />
    </Stepper.Content>
  </Stepper.Root>
);

const StepTwo = () => {
  const stepper = useStepper();

  return (
    <div>Step {stepper.currentStep}</div>
  )
};

Controller Components

These are wrapper components that don't render any UI themselves. Instead, they conditionally render their children based on the stepper's current state. This gives you fine-grained control over which navigation elements are visible on each step.

You can place any component inside them, such as your custom styled <button>.

All controller components behave as slots, powered by @radix-ui/react-slot.

Stepper.Prev

A controller that renders its children on all steps except the first one. It is ideal for "previous" or "back" buttons.

| Prop | Type | Default | Description | | ---------------- | ----------------- | ------- | ----------------------------------------------------------------------------------- | | children | React.ReactNode | - | Required. The element(s) to render, e.g., <button>. | | showInFirstStep| boolean | false | If set to true, it disables the default rule and shows the children on the first step. |

Stepper.Next

A controller that renders its children on all steps except the last one. It is ideal for "next" or "continue" buttons.

| Prop | Type | Default | Description | | ---------------- | ----------------- | ------- | --------------------------------------------------------------------------------- | | children | React.ReactNode | - | Required. The element(s) to render, e.g., <button>. | | showInLastStep | boolean | false | If set to true, it disables the default rule and shows the children on the last step. |

Stepper.Submit

A controller that only renders its children on the last step. It is ideal for "submit" or "finish" buttons. This component has no override props.

| Prop | Type | Default | Description | | ---------- | ----------------- | ------- | ------------------------------------------------------- | | children | React.ReactNode | - | Required. The element(s) to render, e.g., <button>. |

Overriding Default Components

If you need different display logic for your navigation controls, you can easily replace the original components with your own.

The pattern is to define a new component that uses the useStepper hook to access the stepper's state and actions. Then, you can assign your custom component to the Stepper object, overwriting the default implementation.

For example, let's create a custom Stepper.Prev button:

import { Stepper, useStepper } from 'react-headless-stepper';

// Overwrite the default Stepper.Prev component
Stepper.Prev = () => {
  const { goToPrev, isFirstStep } = useStepper();

  // Return null if it's the first step (or add any other custom logic)
  if (isFirstStep) {
    return null;
  }

  return (
    <button type="button" onClick={goToPrev}>
      Custom Previous Button Here
    </button>
  );
};

You can then use it in your application just like the original:

  <Stepper.Root>
    {/* ... */}
    <Stepper.Prev />
  </Stepper.Root>

Controlling the Stepper: Initial State and Callbacks

Stepper.Root

The Stepper.Root component is the main container and state provider for the entire stepper system. It manages the current step state and the total number of steps.

Props

| Prop | Type | Required | Description | | -------------- | ---------- | -------- | ------------------------------------------------------------------------- | | initialStep | number | No | Sets the initial step to be displayed when the component mounts. Defaults to 1. | | onStepChange | function | No | A callback function that is executed whenever the current step changes. |

Usage Example

<Stepper.Root 
  onStepChange={() => console.log('callback')} 
  initialStep={1}
>
  {/* Child components here */}
</Stepper.Root>

Contributing

Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

We want to make contributing to this project as easy and transparent as possible. Here's a quick guide on how you can help.

1. Setting Up the Development Environment

First, fork the repository and clone it to your local machine. Then, navigate to the project's root directory and install the necessary dependencies:

npm install

This project includes an example folder which serves as a testing ground for the library. To run the example project:

# Navigate to the example directory
cd example

# Install its dependencies
npm install

# Start the development server
npm run dev

Now you can make changes to the library's source code in the src folder, and they will be reflected in the example project.

2. Creating a Pull Request

We use a structured commit message format to keep our history clean and organized. This project is configured with Commitizen, Husky, and Commitlint to enforce this standard.

Instead of using git commit, you should use the following command:

npm run commit

This will launch an interactive command-line prompt that will guide you through creating a compliant commit message.

After committing your changes, push them to your fork and open a Pull Request against the main branch of the original repository.

Development Tools Used

Husky: Runs checks automatically before you commit and push to ensure code quality and commit message format.

Commitlint: Ensures that your commit messages follow the Conventional Commits specification.

Commitizen: An interactive tool to help you craft commit messages that adhere to the standard.

Biome.js: Used for code formatting and linting to ensure code quality and consistency across the project. 

By following these guidelines, you help us maintain a high-quality and easy-to-understand codebase. We look forward to your contributions!