CSS-Only

Stepper

Progress indicator showing sequential steps with customizable states, sizes, and orientations. Works by default, enhances with data attributes.

Example

  1. 1
    Account
  2. 2
    Profile
  3. 3
    Complete
<ol class="omni-stepper">
  <li class="omni-step" data-state="completed">
    <div class="omni-step-indicator">1</div>
    <div class="omni-step-content">
      <div class="omni-step-title">Account</div>
    </div>
  </li>
  <li class="omni-step" data-state="active">
    <div class="omni-step-indicator" aria-current="step">2</div>
    <div class="omni-step-content">
      <div class="omni-step-title">Profile</div>
    </div>
  </li>
  <li class="omni-step">
    <div class="omni-step-indicator">3</div>
    <div class="omni-step-content">
      <div class="omni-step-title">Complete</div>
    </div>
  </li>
</ol>

States

Use data-state to indicate step progress:

Default (Pending)

Steps without a state are pending (not yet reached):

  1. 1
    Pending Step
  2. 2
    Not Started

Active

Current step in progress. Include aria-current="step" on the indicator:

  1. 1
    Active Step
  2. 2
    Next Step

Completed

Steps that have been finished:

  1. Completed Step
  2. 2
    Current Step
<li class="omni-step" data-state="completed">
  <div class="omni-step-indicator">
    <svg viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
      <path d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"/>
    </svg>
  </div>
  <div class="omni-step-content">
    <div class="omni-step-title">Completed Step</div>
  </div>
</li>

Sizes

Use data-size to adjust stepper dimensions:

Small

  1. 1
    Step One
  2. 2
    Step Two
  3. 3
    Step Three

Medium (default)

  1. 1
    Step One
  2. 2
    Step Two
  3. 3
    Step Three

Large

  1. 1
    Step One
  2. 2
    Step Two
  3. 3
    Step Three
<ol class="omni-stepper" data-size="sm">...</ol>
<ol class="omni-stepper">...</ol>
<ol class="omni-stepper" data-size="lg">...</ol>

Orientation

Horizontal (default)

Steps arranged in a row with connecting lines:

  1. 1
    Account Created
  2. 2
    Setup Profile
  3. 3
    Get Started

Vertical

Use data-orientation="vertical" for stacked steps:

  1. Account Information
  2. 2
    Personal Details
  3. 3
    Preferences
  4. 4
    Review & Complete
<ol class="omni-stepper" data-orientation="vertical">
  <li class="omni-step" data-state="completed">
    <div class="omni-step-indicator">
      <svg viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
        <path d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"/>
      </svg>
    </div>
    <div class="omni-step-content">
      <div class="omni-step-title">Account Information</div>
    </div>
  </li>
  <!-- More steps... -->
</ol>

Interactive Steps

Wrap steps in .omni-step-link anchor elements to make them clickable. Completed steps are commonly made interactive to allow users to go back:

  1. 1
    Shipping
  2. 2
    Payment
  3. 3
    Confirm
<ol class="omni-stepper">
  <li class="omni-step" data-state="completed">
    <a href="#step-1" class="omni-step-link">
      <div class="omni-step-indicator">1</div>
      <div class="omni-step-content">
        <div class="omni-step-title">Shipping</div>
      </div>
    </a>
  </li>
  <!-- More steps... -->
</ol>

Full Example

Complete checkout flow with mixed states and interactive completed steps:

  1. Cart
  2. Shipping
  3. 3
    Payment
  4. 4
    Review
  5. 5
    Complete

API Reference

Stepper Container

Class Element Description
.omni-stepper <ol> or <ul> Container for step items

Stepper Attributes

Attribute Values Default Description
data-size sm, md, lg md Stepper size (indicator and spacing)
data-orientation horizontal, vertical horizontal Layout direction

Step Elements

Class Element Description
.omni-step <li> Individual step container
.omni-step-indicator <div> Circular indicator (number or icon)
.omni-step-content <div> Wrapper for step text content
.omni-step-title <div> Step label text
.omni-step-link <a> Makes step interactive (wrap indicator and content)

Step Attributes

Attribute Values Default Description
data-state active, completed Step progress state (omit for pending)

ARIA Attributes

Attribute Element Required Description
aria-current="step" .omni-step-indicator Yes (on active step) Indicates current step for screen readers

Accessibility

  • Use semantic <ol> element to convey step order
  • Include aria-current="step" on the active step indicator
  • Interactive steps have visible focus indicators with proper color contrast
  • Completed step links show hover states for discoverability
  • High contrast mode adds additional outlines to active/completed indicators
  • Connecting lines provide visual progress without conveying critical information
  • Consider adding aria-label to the stepper describing the overall process
  • For complex flows, consider adding step descriptions or status text for screen reader users

Best Practices

<!-- Add descriptive label to stepper -->
<ol class="omni-stepper" aria-label="Checkout progress">
  <li class="omni-step" data-state="completed">
    <a href="#cart" class="omni-step-link" aria-label="Cart: Completed">
      <div class="omni-step-indicator">
        <svg>...checkmark...</svg>
      </div>
      <div class="omni-step-content">
        <div class="omni-step-title">Cart</div>
      </div>
    </a>
  </li>
  <li class="omni-step" data-state="active">
    <div class="omni-step-indicator" aria-current="step">2</div>
    <div class="omni-step-content">
      <div class="omni-step-title">Payment</div>
    </div>
  </li>
</ol>