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

@preline/stepper

v4.2.0

Published

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

Readme

Stepper

Dynamic stepper plugin that guides users through the steps of a task.

npm License: MIT Demo

Contents

Overview

The Stepper component provides a multi-step wizard interface that guides users through a sequential process. It supports both linear (sequential) and non-linear (jumpable) modes, with options for optional steps, error states, and completion tracking.

Key Features:

  • Multi-step wizard interface
  • Linear and non-linear navigation modes
  • Optional steps support
  • Error and processing states
  • Completion tracking
  • Programmatic control via JavaScript API
  • Event system for step transitions
  • Accessibility attributes (ARIA) built-in

Installation

To get started, install Stepper plugin via npm, else you can skip this step if you are already using Preline UI as a package.

npm i @preline/stepper

CSS

Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.

@import "tailwindcss";

/* @preline/stepper */
@source "../node_modules/@preline/stepper/*.js";
@import "./node_modules/@preline/stepper/variants.css";
@import "./node_modules/@preline/stepper/theme.css";

JavaScript

Include the JavaScript that powers the interactive elements near the end of your </body> tag:

<script src="./node_modules/@preline/stepper/index.js"></script>

Manual Initialization

Use the non-auto entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.

<script type="module">
  import HSStepper from "@preline/stepper/non-auto.mjs";

  new HSStepper(document.querySelector("#stepper"));
</script>

Via Bundler

When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.

@preline/stepper is the auto-init entry: it scans the DOM and initializes matching elements automatically.

import "@preline/stepper";

@preline/stepper/non-auto is the manual entry: use it when you want explicit control over when initialization happens, either via autoInit() or by creating a specific instance yourself.

import HSStepper from "@preline/stepper/non-auto";

HSStepper.autoInit();

// Or initialize a specific element manually
const el = document.querySelector("#stepper");
if (el) new HSStepper(el);

TypeScript

This package ships with TypeScript type definitions. No additional @types/ package is needed.

Basic usage

The following example demonstrates the minimal HTML structure required for a stepper component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The example shows three steps with navigation buttons.

<div data-hs-stepper>
  <div class="hs-stepper-active:text-blue-500 hs-stepper-success:text-blue-500" data-hs-stepper-nav-item='{
    "index": 1
  }'>
    1 Step
  </div>
  <div class="hs-stepper-active:text-blue-500 hs-stepper-success:text-blue-500" data-hs-stepper-nav-item='{
    "index": 2
  }'>
    2 Step
  </div>
  <div class="hs-stepper-active:text-blue-500 hs-stepper-success:text-blue-500" data-hs-stepper-nav-item='{
    "index": 3
  }'>
    3 Step
  </div>
  
  <div data-hs-stepper-content-item='{
    "index": 1
  }' style="display: none;">
    First content.
  </div>
  <div data-hs-stepper-content-item='{
    "index": 2
  }' style="display: none;">
    Second content.
  </div>
  <div data-hs-stepper-content-item='{
    "index": 3
  }' style="display: none;">
    Third content.
  </div>
  <div data-hs-stepper-content-item='{
    "isFinal": true
  }' style="display: none;">
    Final content.
  </div>
  
  <button class="hs-stepper-disabled:opacity-50" type="button" data-hs-stepper-back-btn>
    Back
  </button>
  <button type="button" data-hs-stepper-skip-btn style="display: none;">
    Skip
  </button>
  <button type="button" data-hs-stepper-next-btn>
    Next
  </button>
  <button type="button" data-hs-stepper-finish-btn style="display: none;">
    Finish
  </button>
  <button type="reset" data-hs-stepper-reset-btn style="display: none;">
    Reset
  </button>
</div>

Structure Requirements:

  • data-hs-stepper: Required on the container element
  • data-hs-stepper-nav-item: Required on each navigation item
  • data-hs-stepper-content-item: Required on each content panel
  • data-hs-stepper-back-btn: Optional back button
  • data-hs-stepper-next-btn: Optional next button
  • data-hs-stepper-finish-btn: Optional finish button
  • data-hs-stepper-skip-btn: Optional skip button
  • data-hs-stepper-reset-btn: Optional reset button

Initial State:

  • First step is active by default (index 1)
  • Content items should have style="display: none;" except the first one
  • Navigation buttons visibility is controlled by the plugin

Configuration Options

Data Options

Data options are specified in the data-hs-stepper, data-hs-stepper-nav-item, and data-hs-stepper-content-item attributes.

| Attribute | Target Element | Type | Default | Description | | --- | --- | --- | --- | --- | | data-hs-stepper | Container | - | - | Activate a Stepper by specifying on an element. Should be added to the container. | | :currentIndex | Inside data-hs-stepper | number | 1 | Index of the current step. This must be a number between 1 and the maximum number of steps. | | :mode | Inside data-hs-stepper | "linear" | "non-linear" | "linear" | The mode of the stepper. In "non-linear" mode, the user can navigate to any step and nav items are clickable. In "linear" mode, the user can only navigate to the next/back step. | | :isCompleted | Inside data-hs-stepper | boolean | false | Whether the stepper is completed. | | data-hs-stepper-nav-item | Navigation item | - | - | Activate a Stepper Nav Item by specifying on an element. Should be added to the nav item. | | :index | Inside data-hs-stepper-nav-item | number | - | The index of the step to which the item belongs. This must be a number between 1 and the maximum number of steps. | | :isOptional | Inside data-hs-stepper-nav-item | boolean | false | Whether the step is optional. | | :isCompleted | Inside data-hs-stepper-nav-item | boolean | false | Whether the step is completed. | | :isSkip | Inside data-hs-stepper-nav-item | boolean | false | Whether the step is skipped. | | :hasError | Inside data-hs-stepper-nav-item | boolean | false | Whether the step has an error. | | data-hs-stepper-content-item | Content item | - | - | Activate a Stepper Content Item by specifying on an element. Should be added to the content item. | | :index | Inside data-hs-stepper-content-item | number | - | The index of the step to which the item belongs. This must be a number between 1 and the maximum number of steps. | | :isCompleted | Inside data-hs-stepper-content-item | boolean | false | Whether the step is completed. | | :isSkip | Inside data-hs-stepper-content-item | boolean | false | Whether the step is skipped. | | :isFinal | Inside data-hs-stepper-content-item | boolean | false | Whether the step is final. |

Tailwind Modifiers

| Name | Description | | --- | --- | | hs-stepper-active:* | Modifies the active step. | | hs-stepper-success:* | Modifies the completed step. | | hs-stepper-disabled:* | Modifies the "back" button when the very first step is active. | | hs-stepper-skipped:* | Modifies the skipped step. | | hs-stepper-error:* | Modifies the step that has error. Error class should be added manually by some event. E.g. after form validation. | | hs-stepper-process:* | Modifies the step that processing. Process class should be added manually by some event. E.g. after form submit. | | hs-stepper-completed:* | Modifies all steps are completed. |

JavaScript API

The HSStepper object is available in the global window object after the plugin is loaded.

Instance Methods

These methods are called on a stepper instance.

| Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | setProcessedNavItem(n) | n: number | void | Set the nav item as processed. n is the index of the step to which the item belongs. | | setErrorNavItem(n) | n: number | void | Set the nav item as error. n is the index of the step to which the item belongs. | | unsetProcessedNavItem(n) | n: number | void | Unset the nav item as processed. n is the index of the step to which the item belongs. | | goToNext() | None | number | Go to the next step. Returns the index of the next step. If the current step is the last, returns the index of the current step. | | goToFinish() | None | number | Go to the finish step. Returns the index of the finish step. If the current step is the last, returns the index of the current step. | | disableButtons() | None | void | Disable the "next" and "back" buttons. | | enableButtons() | None | void | Enable the "next" and "back" buttons. | | destroy() | None | void | Destroys the stepper instance, removes all generated markup, classes, and event listeners. Use when removing stepper from DOM. |

Static Methods

These methods are called directly on the HSStepper class.

| Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | HSStepper.getInstance(target, isInstance) | target: HTMLElement \| string (CSS selector)isInstance: boolean (optional) | HSStepper \| { id: string \| number, element: HSStepper } \| null | Returns the stepper instance associated with the target. If isInstance is true, returns collection item object { id, element } where element is the HSStepper instance. If isInstance is false or omitted, returns the HSStepper instance directly. Returns null if stepper instance is not found. |

Usage Examples

Example 1: Using instance methods (public API)

// Create a new stepper instance
const stepper = new HSStepper(document.querySelector('#hs-stepper'));
let errorState = 1;

stepper.on('beforeNext', (index) => {
  if (index === 2) {
    stepper.setProcessedNavItem(index);
    
    setTimeout(() => {
      stepper.unsetProcessedNavItem(index);
      stepper.enableButtons();
      
      if (errorState) {
        stepper.goToNext();
      } else {
        stepper.setErrorNavItem(index);
      }
      
      errorState = !errorState;
    }, 2000);
  }
});

Example 2: Getting instance and using methods (recommended pattern)

// Get the stepper instance
const instance = HSStepper.getInstance('#hs-stepper', true);

if (instance) {
  const { element } = instance; // element is the HSStepper instance
  let errorState = 1;

  element.on('beforeNext', (index) => {
    if (index === 2) {
      element.setProcessedNavItem(index);
      
      setTimeout(() => {
        element.unsetProcessedNavItem(index);
        element.enableButtons();
        
        if (errorState) {
          element.goToNext();
        } else {
          element.setErrorNavItem(index);
        }
        
        errorState = !errorState;
      }, 2000);
    }
  });

  // Clean up when removing from DOM
  function removeStepper() {
    element.destroy();
  }
}

Example 3: Programmatic navigation

const instance = HSStepper.getInstance('#hs-stepper', true);
if (instance) {
  const { element } = instance;
  // Navigate to next step
  const nextIndex = element.goToNext();
  console.log('Moved to step:', nextIndex);
  // Navigate to finish
  const finishIndex = element.goToFinish();

  console.log('Finished at step:', finishIndex);
}

Example 4: Destroying stepper instance

const instance = HSStepper.getInstance('#hs-stepper', true);

if (instance) {
  const { element } = instance;
  const removeBtn = document.querySelector('#hs-remove-btn');

  removeBtn.addEventListener('click', () => {
    // Clean up before removing from DOM
    element.destroy();
    // Now safe to remove the element
    document.querySelector('#hs-stepper').remove();
  });
}

Events

Stepper instances emit events that can be listened to for step transitions and custom behavior.

| Event Name | When Fired | Callback Parameter | Description | | --- | --- | --- | --- | | on:active | When the "active" class is set up | currentIndex (number) | Fires when a step becomes active. | | on:beforeNext | Before the "next" button is clicked | currentIndex (number) | Fires before navigating to the next step. Can be used to validate or prevent navigation. | | on:beforeFinish | Before the "finish" button is clicked | currentIndex (number) | Fires before finishing the stepper. Can be used to validate or prevent completion. | | on:next | When the "next" button is clicked | currentIndex (number) | Fires when navigating to the next step. | | on:back | When the "back" button is clicked | currentIndex (number) | Fires when navigating to the previous step. | | on:complete | When the "complete" button is clicked | currentIndex (number) | Fires when completing a step. | | on:finish | When the "finish" button is clicked | currentIndex (number) | Fires when finishing the stepper. |

Event Usage Example

// Get stepper instance
const instance = HSStepper.getInstance('#hs-stepper', true);

if (instance) {
  const { element } = instance;

  // Listen to step activation
  element.on('active', (currentIndex) => {
    console.log('Step activated:', currentIndex);
    // Perform actions when step becomes active
    // e.g., load content, initialize form fields
  });

  // Listen to before next (for validation)
  element.on('beforeNext', (currentIndex) => {
    console.log('Before next step:', currentIndex);
    // Validate current step before proceeding
    // Can prevent navigation if validation fails
  });

  // Listen to finish
  element.on('finish', (currentIndex) => {
    console.log('Stepper finished:', currentIndex);
    // Perform final actions
    // e.g., submit form, show success message
  });
}

Common Patterns

Pattern 1: Non-linear Mode

Allow users to jump to any step.

<div data-hs-stepper='{
  "mode": "non-linear"
}'>
  <!-- Stepper content -->
</div>

Pattern 2: Error Handling

Set error state on a step after validation fails.

<div id="hs-stepper-first" data-hs-stepper>
  <!-- Stepper content -->
</div>

<script>
  const instance = HSStepper.getInstance('#hs-stepper-first', true);
  
  if (instance) {
    const { element } = instance;

    // Validate and set error if needed
    function validateStep(stepIndex) {
      // Validation logic
      if (validationFails) {
        element.setErrorNavItem(stepIndex);
      }
    }
  }
</script>

License

Copyright (c) 2026 Preline Labs.

Licensed under the MIT License.