Navigation

Stepper

Shows where someone is in a multi-step process and links back to the steps they have done.

Built on
<nav><ol>aria-current
Client JavaScript
None
Works without React
Yes, as HTML and CSS
Source, gzipped
2.7 kB
Dependencies
React
Try its options

Loading its options.

Code
import { Step, Stepper } from "@/components/equip/stepper";

export default function Demo() {
  return (
    <Stepper label="Checkout progress" current={2} style={{ width: 224 }}>
      <Step title="Cart" href="#cart" />
      <Step title="Shipping" href="#shipping" />
      <Step title="Payment" />
      <Step title="Review" />
    </Stepper>
  );
}
Your versionchange its options in Look, This part
HTMLworks in any framework, with the part's CSS
<nav style="width:224px" aria-label="Checkout progress" class="eq-stepper" data-orientation="horizontal">
  <ol class="eq-stepper-list">
    <li class="eq-stepper-step" data-status="done">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">1</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <a class="eq-stepper-title" href="#cart">Cart</a>
        <span class="eq-stepper-status">, Completed</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="done">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">2</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <a class="eq-stepper-title" href="#shipping">Shipping</a>
        <span class="eq-stepper-status">, Completed</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="current" aria-current="step">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">3</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Payment</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="upcoming">
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">4</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Review</span>
      </span>
    </li>
  </ol>
</nav>

Examples

Vertical with descriptions

Done steps with an href become links back, so people can revisit a step without losing their place.

Code
import { Step, Stepper } from "@/components/equip/stepper";

export default function Example() {
  return (
    <Stepper label="Workspace setup" orientation="vertical" current={1} style={{ width: "100%", maxWidth: 280 }}>
      <Step title="Create workspace" description="Acme Robotics, eu-west-1" href="#workspace" />
      <Step title="Connect repository" description="Pick a GitHub org and the repos to import." />
      <Step title="Invite teammates" description="Send invites now or share a link later." />
      <Step title="Deploy" description="First build runs on the main branch." />
    </Stepper>
  );
}
HTMLworks in any framework, with the part's CSS
<nav style="width:100%;max-width:280px" aria-label="Workspace setup" class="eq-stepper" data-orientation="vertical">
  <ol class="eq-stepper-list">
    <li class="eq-stepper-step" data-status="done">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">1</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <a class="eq-stepper-title" href="#workspace">Create workspace</a>
        <span class="eq-stepper-status">, Completed</span>
        <span class="eq-stepper-description">Acme Robotics, eu-west-1</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="current" aria-current="step">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">2</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Connect repository</span>
        <span class="eq-stepper-description">Pick a GitHub org and the repos to import.</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="upcoming">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">3</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Invite teammates</span>
        <span class="eq-stepper-description">Send invites now or share a link later.</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="upcoming">
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">4</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Deploy</span>
        <span class="eq-stepper-description">First build runs on the main branch.</span>
      </span>
    </li>
  </ol>
</nav>

A step that needs attention

state="error" swaps the marker for a warning mark and tells screen readers the step needs attention.

Code
import { Step, Stepper } from "@/components/equip/stepper";

export default function Example() {
  return (
    <Stepper label="Import progress" orientation="vertical" current={2} style={{ width: "100%", maxWidth: 280 }}>
      <Step title="Upload CSV" description="customers-2026-q3.csv, 4,812 rows" href="#upload" />
      <Step title="Map columns" description="2 columns could not be matched" href="#map" state="error" />
      <Step title="Review duplicates" description="Waiting on column mapping" />
      <Step title="Import" />
    </Stepper>
  );
}
HTMLworks in any framework, with the part's CSS
<nav style="width:100%;max-width:280px" aria-label="Import progress" class="eq-stepper" data-orientation="vertical">
  <ol class="eq-stepper-list">
    <li class="eq-stepper-step" data-status="done">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">1</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <a class="eq-stepper-title" href="#upload">Upload CSV</a>
        <span class="eq-stepper-status">, Completed</span>
        <span class="eq-stepper-description">customers-2026-q3.csv, 4,812 rows</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="done" data-state="error">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">2</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <a class="eq-stepper-title" href="#map">Map columns</a>
        <span class="eq-stepper-status">, Needs attention</span>
        <span class="eq-stepper-description">2 columns could not be matched</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="current" aria-current="step">
      <span class="eq-stepper-connector" aria-hidden="true"></span>
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">3</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Review duplicates</span>
        <span class="eq-stepper-description">Waiting on column mapping</span>
      </span>
    </li>
    <li class="eq-stepper-step" data-status="upcoming">
      <span class="eq-stepper-marker" aria-hidden="true">
        <span class="eq-stepper-number">4</span>
        <svg class="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3.5 8.5l3 3 6-7" pathLength="1" />
        </svg>
        <svg class="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
          <path d="M8 4.5v4.25M8 11.25v.25" />
        </svg>
      </span>
      <span class="eq-stepper-text">
        <span class="eq-stepper-title">Import</span>
      </span>
    </li>
  </ol>
</nav>

Props

PropTypeDefaultWhat it does
labelstringnoneNames the navigation landmark, e.g. "Checkout progress".
orientation"horizontal" | "vertical""horizontal"A row of equal columns, or a column with room for descriptions.
currentnumbernoneIndex of the step the person is on. Every step before it is done.
childrenReactNodenoneStep elements, as direct children.
...restComponentProps<"nav">noneEvery native nav attribute, including id and style.
Step titleReactNodenoneThe step's name.
Step descriptionReactNodenoneA line under the title, such as what was chosen.
Step hrefstringnoneWhere the step links to once it is done. Current and upcoming steps never link.
Step state"error"noneMarks the step as needing attention with a warning mark and danger colour.

Anatomy

root.eq-stepperThe nav landmark.
list.eq-stepper-listAn ordered list, so the count is announced.
step.eq-stepper-stepdata-status is done, current or upcoming.
connector.eq-stepper-connectorThe line to the next step. It fills when the step is done.
marker.eq-stepper-marker
number.eq-stepper-number
tick.eq-stepper-tickDrawn in when the step becomes done.
alert.eq-stepper-alertThe warning mark for state="error".
text.eq-stepper-text
title.eq-stepper-titleA link on done steps with an href.
description.eq-stepper-description
status.eq-stepper-statusVisually hidden "Completed" or "Needs attention".

Keyboard

TabMoves between the links of done steps.

Notes

  • The current step has aria-current="step"; done and failed steps carry visually hidden status text, because the marks are hidden from assistive tech.
  • Step only describes a step and renders nothing on its own: Stepper reads each Step's props, so Steps must be its direct children.
  • It reports progress and links back; it holds no form state. For the steps' content and Next and Back buttons, use Wizard.
  • Renders on the server with no client JavaScript. Change current and the connector fills and the tick draws in.
  • Horizontal columns are equal widths, so keep titles to a word or two; use vertical when steps need descriptions.

Source

Two files, and they are the whole part. Open either to read it, copy it straight from its bar, or add the part to your loadout and install it with everything else you picked.

components/equip/stepper.tsx88 lines
import { Children, isValidElement, type ComponentProps, type ReactNode } from "react";
import "./stepper.css";

export type StepperProps = Omit<ComponentProps<"nav">, "children"> & {
  /** Names the navigation landmark, e.g. "Checkout progress". */
  label: string;
  orientation?: "horizontal" | "vertical";
  /** Index of the step the person is on. Steps before it are done. */
  current: number;
  /** Step elements, as direct children. */
  children: ReactNode;
};

export type StepProps = {
  title: ReactNode;
  description?: ReactNode;
  /** Where a done step links back to. Upcoming and current steps never link. */
  href?: string;
  /** Marks the step as failed or needing attention. */
  state?: "error";
};

/** Describes one step. Stepper reads these props and draws the step, so a Step must be its direct child. */
export function Step(_props: StepProps): null {
  return null;
}

export function Stepper({
  label,
  orientation = "horizontal",
  current,
  className,
  children,
  ...rest
}: StepperProps) {
  const steps = Children.toArray(children).filter(
    (child) => isValidElement<StepProps>(child) && child.type === Step,
  ) as { props: StepProps }[];

  return (
    <nav
      {...rest}
      aria-label={label}
      className={["eq-stepper", className].filter(Boolean).join(" ")}
      data-orientation={orientation}
    >
      <ol className="eq-stepper-list">
        {steps.map(({ props: step }, index) => {
          const status = index < current ? "done" : index === current ? "current" : "upcoming";
          const error = step.state === "error";
          const link = status === "done" && step.href;
          const statusText = error ? "Needs attention" : status === "done" ? "Completed" : null;
          return (
            <li
              key={index}
              className="eq-stepper-step"
              data-status={status}
              data-state={step.state}
              aria-current={status === "current" ? "step" : undefined}
            >
              {index < steps.length - 1 && <span className="eq-stepper-connector" aria-hidden="true" />}
              <span className="eq-stepper-marker" aria-hidden="true">
                <span className="eq-stepper-number">{index + 1}</span>
                <svg className="eq-stepper-tick" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M3.5 8.5l3 3 6-7" pathLength={1} />
                </svg>
                <svg className="eq-stepper-alert" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
                  <path d="M8 4.5v4.25M8 11.25v.25" />
                </svg>
              </span>
              <span className="eq-stepper-text">
                {link ? (
                  <a className="eq-stepper-title" href={step.href}>
                    {step.title}
                  </a>
                ) : (
                  <span className="eq-stepper-title">{step.title}</span>
                )}
                {statusText && <span className="eq-stepper-status">, {statusText}</span>}
                {step.description != null && <span className="eq-stepper-description">{step.description}</span>}
              </span>
            </li>
          );
        })}
      </ol>
    </nav>
  );
}
components/equip/stepper.css255 lines
@layer equip {
  .eq-stepper {
    --_marker: 24px;
    --_gap: var(--eq-space-1);

    color: var(--eq-ink);
    font: var(--eq-weight) var(--eq-text-s) / 1.3 var(--eq-font);
  }

  .eq-stepper-list {
    display: flex;
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .eq-stepper-step {
    position: relative;
    min-width: 0;
  }

  /* Horizontal: equal columns, marker on top, text centred under it. */
  .eq-stepper[data-orientation="horizontal"] .eq-stepper-step {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--eq-space-2);
    padding-inline: 2px;
    text-align: center;
  }

  .eq-stepper[data-orientation="vertical"] .eq-stepper-list {
    flex-direction: column;
  }

  .eq-stepper[data-orientation="vertical"] .eq-stepper-step {
    display: grid;
    grid-template-columns: var(--_marker) 1fr;
    column-gap: var(--eq-space-3);
    padding-bottom: var(--eq-space-4);
  }

  .eq-stepper[data-orientation="vertical"] .eq-stepper-step:last-child {
    padding-bottom: 0;
  }

  /* The line leading out of a step to the next one. It fills once the step is done. */
  .eq-stepper-connector {
    position: absolute;
    background: var(--eq-line-strong);
    overflow: hidden;
  }

  .eq-stepper[data-orientation="horizontal"] .eq-stepper-connector {
    top: calc(var(--_marker) / 2 - 1px);
    height: 2px;
    left: calc(50% + var(--_marker) / 2 + var(--_gap));
    right: calc(-50% + var(--_marker) / 2 + var(--_gap));
    border-radius: var(--eq-radius-full);
  }

  .eq-stepper[data-orientation="vertical"] .eq-stepper-connector {
    left: calc(var(--_marker) / 2 - 1px);
    width: 2px;
    top: calc(var(--_marker) + var(--_gap));
    bottom: var(--_gap);
    border-radius: var(--eq-radius-full);
  }

  .eq-stepper-connector::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--eq-solid);
    scale: 0 1;
    transform-origin: left center;
    transition: scale var(--eq-dur-move) var(--eq-spring);
  }

  .eq-stepper[data-orientation="vertical"] .eq-stepper-connector::after {
    scale: 1 0;
    transform-origin: center top;
  }

  .eq-stepper-step[data-status="done"] .eq-stepper-connector::after {
    scale: 1;
  }

  .eq-stepper-marker {
    position: relative;
    flex: none;
    display: grid;
    place-items: center;
    box-sizing: border-box;
    width: var(--_marker);
    height: var(--_marker);
    border: 1px solid var(--eq-line-strong);
    border-radius: var(--eq-radius-full);
    background: var(--eq-raised);
    color: var(--eq-ink-3);
    font: var(--eq-weight-strong) var(--eq-text-xs) / 1 var(--eq-font);
    font-variant-numeric: tabular-nums;
    transition:
      background-color var(--eq-dur) var(--eq-ease),
      border-color var(--eq-dur) var(--eq-ease),
      color var(--eq-dur) var(--eq-ease);
  }

  .eq-stepper-marker > * {
    grid-area: 1 / 1;
  }

  .eq-stepper-step[data-status="current"] .eq-stepper-marker {
    border: 2px solid var(--eq-ink);
    color: var(--eq-ink);
  }

  .eq-stepper-step[data-status="done"] .eq-stepper-marker {
    border-color: var(--eq-solid);
    background: var(--eq-solid);
    color: var(--eq-solid-ink);
  }

  .eq-stepper-step[data-state="error"] .eq-stepper-marker {
    border: 2px solid var(--eq-danger);
    background: var(--eq-raised);
    color: var(--eq-danger);
  }

  .eq-stepper-tick,
  .eq-stepper-alert {
    width: 14px;
    height: 14px;
    opacity: 0;
    transition: opacity var(--eq-dur) var(--eq-ease);
  }

  /* The tick draws along its stroke when a step becomes done (the path has pathLength="1"). */
  .eq-stepper-tick > path {
    stroke-dasharray: 2 3;
    stroke-dashoffset: 2;
    transition: stroke-dashoffset var(--eq-dur) var(--eq-ease);
  }

  .eq-stepper-number {
    transition: opacity var(--eq-dur) var(--eq-ease);
  }

  .eq-stepper-step:is([data-status="done"], [data-state="error"]) .eq-stepper-number {
    opacity: 0;
  }

  .eq-stepper-step[data-status="done"]:not([data-state="error"]) .eq-stepper-tick {
    opacity: 1;
  }

  .eq-stepper-step[data-status="done"]:not([data-state="error"]) .eq-stepper-tick > path {
    stroke-dashoffset: 1;
    transition: stroke-dashoffset var(--eq-dur-move) var(--eq-spring);
  }

  .eq-stepper-step[data-state="error"] .eq-stepper-alert {
    opacity: 1;
  }

  .eq-stepper-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }

  .eq-stepper[data-orientation="horizontal"] .eq-stepper-text {
    align-items: center;
    max-width: 100%;
    font-size: var(--eq-text-xs);
  }

  .eq-stepper[data-orientation="vertical"] .eq-stepper-text {
    /* Centres a one-line title on the marker. */
    padding-top: calc((var(--_marker) - 1.3em) / 2);
  }

  .eq-stepper-title {
    max-width: 100%;
    color: var(--eq-ink-2);
    font-weight: var(--eq-weight-strong);
    overflow-wrap: anywhere;
  }

  .eq-stepper-step[data-status="current"] .eq-stepper-title {
    color: var(--eq-ink);
  }

  .eq-stepper-step[data-status="upcoming"] .eq-stepper-title {
    color: var(--eq-ink-3);
    font-weight: var(--eq-weight);
  }

  .eq-stepper-step[data-state="error"] .eq-stepper-title {
    color: var(--eq-danger);
  }

  /* Padding keeps the link a 24px target without moving the text. */
  a.eq-stepper-title {
    display: inline-block;
    padding-block: 5px;
    margin-block: -5px;
    border-radius: var(--eq-radius-s);
    text-decoration: underline;
    text-decoration-color: var(--eq-line-strong);
    text-underline-offset: 3px;
    transition:
      color var(--eq-dur) var(--eq-ease),
      text-decoration-color var(--eq-dur) var(--eq-ease),
      scale var(--eq-dur) var(--eq-ease);
  }

  @media (hover: hover) {
    a.eq-stepper-title:hover {
      color: var(--eq-ink);
      text-decoration-color: currentColor;
    }
  }

  a.eq-stepper-title:active {
    scale: var(--eq-press);
  }

  a.eq-stepper-title:focus-visible {
    outline: 2px solid var(--eq-focus);
    outline-offset: 2px;
  }

  .eq-stepper-description {
    color: var(--eq-ink-2);
    font-size: var(--eq-text-xs);
  }

  .eq-stepper-step[data-status="upcoming"] .eq-stepper-description {
    color: var(--eq-ink-3);
  }

  /* Read by screen readers, not shown: the marker says the same thing with a tick. */
  .eq-stepper-status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

EqUIp is in beta: free for non-commercial use, no warranty, and things can change. Terms

Nothing picked yet. Press A on a part, or use the plus on the board, and the install command builds here.

Loading the index.

Loading the index