Numbered How It Works Steps in a Row

A how it works section with four numbered steps. On desktop the steps sit in one row, joined by a thin line that runs from each square number to the next, with a title, a short description and a time estimate under each. A heading and one button sit above the row. On phones and tablets the row turns into a vertical timeline: numbers down the left edge, joined by a vertical line, with the text beside them.

Code

const steps = [
  {
    title: "Tell us about your roof",
    text: "Enter your address and a recent electricity bill. We size a system from satellite imagery and your real usage.",
    when: "5 minutes",
  },
  {
    title: "Get a fixed quote",
    text: "One price covering panels, inverter, scaffolding and paperwork, with the yearly saving we expect written beside it.",
    when: "Next working day",
  },
  {
    title: "We fit it in a day",
    text: "Two certified installers arrive at eight, the panels are on by mid afternoon and the roof is left as tidy as we found it.",
    when: "Within 3 weeks",
  },
  {
    title: "Watch the meter slow down",
    text: "The app shows what you generate, use and sell back each hour. We monitor the system and call you if anything dips.",
    when: "From day one",
  },
];

export default function NumberedHowItWorksStepsInARow() {
  return (
    <section className="bg-sky-50 px-6 py-16 text-slate-900 sm:py-24">
      <div className="mx-auto max-w-6xl">
        <div className="flex flex-col gap-6 sm:flex-row sm:items-end sm:justify-between">
          <div className="max-w-xl">
            <p className="text-sm font-semibold uppercase tracking-widest text-sky-700">How it works</p>
            <h2 className="mt-3 text-3xl font-semibold tracking-tight sm:text-4xl">From first question to free electricity in four steps</h2>
          </div>
          <a href="#" className="inline-flex min-h-[44px] flex-none items-center justify-center gap-2 self-start bg-slate-900 px-5 text-sm font-semibold text-white transition hover:bg-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-600 focus-visible:ring-offset-2 focus-visible:ring-offset-sky-50 sm:self-auto">
            Start with your address
            <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="h-4 w-4"><path d="M4.5 10h11m-4-4.5L16 10l-4.5 4.5" /></svg>
          </a>
        </div>

        <ol className="mt-14 lg:mt-16 lg:grid lg:grid-cols-4 lg:gap-8">
          {steps.map((s, i) => (
            <li key={s.title} className="relative flex gap-5 pb-10 last:pb-0 lg:block lg:pb-0">
              {i < steps.length - 1 && (
                <>
                  <span aria-hidden="true" className="absolute bottom-1 left-6 top-14 w-px -translate-x-1/2 bg-sky-300 lg:hidden" />
                  <span aria-hidden="true" className="absolute -right-6 left-16 top-6 hidden h-px bg-sky-300 lg:block" />
                </>
              )}
              <span className={`flex h-12 w-12 flex-none items-center justify-center text-base font-semibold tabular-nums ${i === 0 ? "bg-sky-600 text-white" : "bg-white text-sky-800 ring-1 ring-inset ring-sky-300"}`}>
                <span className="sr-only">Step </span>0{i + 1}
              </span>
              <div className="lg:mt-7 lg:pr-4">
                <h3 className="text-lg font-semibold tracking-tight">{s.title}</h3>
                <p className="mt-2 text-sm leading-relaxed text-slate-600">{s.text}</p>
                <p className="mt-4 inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-sky-800">
                  <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="h-4 w-4"><circle cx="10" cy="10" r="7" /><path d="M10 6v4l2.5 2" /></svg>
                  {s.when}
                </p>
              </div>
            </li>
          ))}
        </ol>
      </div>
    </section>
  );
}

Install with one command: npx shadcn@latest add https://we.inc/r/numbered-how-it-works-steps-in-a-row.json

When to use it

How to customize it

Accessibility

Questions

How many steps should a how it works section have?

Three or four. That is enough to show a real process and few enough to read in one glance. If your process has more stages, group the small ones together under one step.

How do I draw a line between steps in Tailwind?

Make each step `relative` and add an absolutely positioned `<span>` one pixel tall that starts after the number and runs to the edge of the column and across the gap. Leave it off the last step.

How does the row become a vertical timeline on mobile?

Below the `lg` breakpoint the list is a normal block and each step is a flex row with the number on the left. A second line, one pixel wide and hidden on desktop, runs down from each number to the next.

Should the steps be clickable?

Usually not. The section explains a process, and one clear button for the first step works better than four links. If a step has its own page, link only its title.

Can I use icons instead of numbers?

You can, but numbers tell the reader there is an order and how far along each step is. If you add icons, keep the numbers as well or keep the list as an `<ol>`.

Related: Three Column Feature Grid with Icons, Alternating Feature Rows with Illustrations, Stats Band with Four Numbers on Dark, Button Set: Primary, Secondary, Ghost, Icon and Loading.

More feature sections or all free UI components. Start for free to have a full site built around it.

More in Feature Sections

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap