COMPONENTS/NAVIGATION

Steps.

Know where you are in a process.

In practice

  1. Details
  2. Team
  3. Review

Presentational ordered progress with a zero-based current index. The current step has aria-current. Your application controls validation and navigation.

Installation

Install Coal once. Components and TypeScript declarations are included. React 19 and React DOM 19 are peer dependencies.

Terminal · local package
npm install http://localhost:3100/downloads/chlohal-coal-ui-0.5.0.tgz

This installs the local package. It is not yet published on npm. See installation for stylesheet setup and integration.

Usage

example.tsx
"use client";
import * as React from "react";
import "@chlohal/coal-ui/styles.css";
import { Steps, Button } from "@chlohal/coal-ui";
export default function Example() {
    const id = React.useId();
    const [page, setPage] = React.useState(1);
    return (<div>
          <Steps steps={[
            { id: "details", label: "Details" },
            { id: "team", label: "Team" },
            { id: "review", label: "Review" },
        ]} current={page - 1}/>
          <Button variant="outline" size="sm" onClick={() => setPage(page === 3 ? 1 : page + 1)}>
            {page === 3 ? "Start again" : "Next step"}
          </Button>
        </div>);
}

Source

The original Coal implementation. Use the package export to integrate it.

packages/react/src/steps.tsx
import * as React from "react";
import { cn } from "./internal.js";
export type StepsProps = React.ComponentPropsWithRef<"ol"> & {
  steps: { id: string; label: string; description?: string }[];
  current: number;
};
export function Steps({ steps, current, className, ...props }: StepsProps) {
  return (
    <ol
      className={cn("coal-steps", className)}
      aria-label="Progress"
      {...props}
    >
      {steps.map((step, i) => (
        <li
          key={step.id}
          aria-current={i === current ? "step" : undefined}
          data-complete={i < current || undefined}
        >
          <span className="coal-step-number" aria-hidden="true">
            {i < current ? "✓" : i + 1}
          </span>
          <div>
            <strong>{step.label}</strong>
            {step.description && <p>{step.description}</p>}
          </div>
        </li>
      ))}
    </ol>
  );
}

Accessibility checklist

  • Provide an accessible name for controls, including icon-only buttons.
  • Check keyboard navigation, visible focus and disabled states in your application.
  • Do not rely on color alone to communicate status.