Open demo

CSS code

HTML
<ol class="proc">
  <li class="stage"><span class="n" aria-hidden="true">1</span>
    <span class="ic" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h10M4 18h13"/></svg></span>
    <h2>Brief</h2><p>You send references and a rough size. Twenty minutes of your time.</p></li>
  <li class="stage"><span class="n" aria-hidden="true">2</span>
    <span class="ic" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 20h4l10-10-4-4L4 16z"/></svg></span>
    <h2>Sketch</h2><p>Two directions in pencil, so nothing expensive gets built on the wrong idea.</p></li>
  <li class="stage"><span class="n" aria-hidden="true">3</span>
    <span class="ic" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg></span>
    <h2>Make</h2><p>Four to six weeks, with photos at the halfway point.</p></li>
  <li class="stage"><span class="n" aria-hidden="true">4</span>
    <span class="ic" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 8l8-4 8 4v8l-8 4-8-4z"/><path d="M4 8l8 4 8-4M12 12v8"/></svg></span>
    <h2>Deliver</h2><p>Crated, insured, and hung if you are within driving distance.</p></li>
</ol>
CSS
/* Icon process: an <ol> of stages; the connector arrows are pseudo-elements drawn in the gap between them. */
.proc{--pr-accent:#4f46e5;--pr-arrow:#c3cbe0;--pr-border:#e3e8f2;--pr-muted:#5f6a86;
  display:flex;align-items:flex-start;width:100%;max-width:900px;gap:42px;margin:0;padding:0;list-style:none}
.proc,.proc *{box-sizing:border-box}
.proc :where(li,h2,p){margin:0;padding:0}
.proc .stage{flex:1;text-align:center;padding:0 10px;position:relative}
.proc .stage:not(:last-child)::before{content:"";position:absolute;left:calc(100% + 2px);top:31px;width:22px;height:2px;background:var(--pr-arrow)}
.proc .stage:not(:last-child)::after{content:"";position:absolute;left:calc(100% + 28px);top:26px;width:0;height:0;
  border:6px solid transparent;border-left-color:var(--pr-arrow)}
.proc .ic{width:62px;height:62px;border-radius:18px;display:grid;place-items:center;margin:0 auto 15px;
  background:#fff;border:1px solid var(--pr-border);box-shadow:0 8px 20px -14px rgba(23,32,58,.4)}
.proc .ic svg{display:block;width:26px;height:26px;stroke:var(--pr-accent);fill:none;stroke-width:1.9}
.proc h2{font-size:.92rem;margin-bottom:5px;letter-spacing:-.01em}
.proc p{font-size:.79rem;color:var(--pr-muted);line-height:1.6}
.proc .n{position:absolute;top:-8px;left:50%;margin-left:14px;width:22px;height:22px;
  border-radius:50%;background:var(--pr-accent);color:#fff;font-size:.7rem;font-weight:800;
  display:grid;place-items:center}
@media(max-width:760px){
  .proc{flex-direction:column;max-width:320px;align-items:stretch;gap:34px}
  .proc .stage:not(:last-child)::before{left:50%;top:calc(100% - 2px);width:2px;height:22px;margin-left:-1px}
  .proc .stage:not(:last-child)::after{left:calc(50% - 6px);top:calc(100% + 26px);
    border-left-color:transparent;border-top-color:var(--pr-arrow)}
}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<ol class="proc list-unstyled d-flex align-items-start w-100 m-0">
  <li class="stage position-relative text-center"><span class="n position-absolute start-50 d-grid rounded-circle text-white" aria-hidden="true">1</span>
    <span class="ic d-grid bg-white" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h10M4 18h13"/></svg></span>
    <h2>Brief</h2><p>You send references and a rough size. Twenty minutes of your time.</p></li>
  <li class="stage position-relative text-center"><span class="n position-absolute start-50 d-grid rounded-circle text-white" aria-hidden="true">2</span>
    <span class="ic d-grid bg-white" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 20h4l10-10-4-4L4 16z"/></svg></span>
    <h2>Sketch</h2><p>Two directions in pencil, so nothing expensive gets built on the wrong idea.</p></li>
  <li class="stage position-relative text-center"><span class="n position-absolute start-50 d-grid rounded-circle text-white" aria-hidden="true">3</span>
    <span class="ic d-grid bg-white" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg></span>
    <h2>Make</h2><p>Four to six weeks, with photos at the halfway point.</p></li>
  <li class="stage position-relative text-center"><span class="n position-absolute start-50 d-grid rounded-circle text-white" aria-hidden="true">4</span>
    <span class="ic d-grid bg-white" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 8l8-4 8 4v8l-8 4-8-4z"/><path d="M4 8l8 4 8-4M12 12v8"/></svg></span>
    <h2>Deliver</h2><p>Crated, insured, and hung if you are within driving distance.</p></li>
</ol>
CSS
/* Bootstrap flex list and utilities; the arrows and the column switch at 760px are custom CSS. */
.proc{--pr-accent:#4f46e5;--pr-arrow:#c3cbe0;--pr-border:#e3e8f2;--pr-muted:#5f6a86;max-width:900px;gap:42px}
.proc .stage{flex:1;padding:0 10px}
.proc .stage:not(:last-child)::before{content:"";position:absolute;left:calc(100% + 2px);top:31px;width:22px;height:2px;background:var(--pr-arrow)}
.proc .stage:not(:last-child)::after{content:"";position:absolute;left:calc(100% + 28px);top:26px;width:0;height:0;
  border:6px solid transparent;border-left-color:var(--pr-arrow)}
.proc .ic{width:62px;height:62px;border-radius:18px;place-items:center;margin:0 auto 15px;
  border:1px solid var(--pr-border);box-shadow:0 8px 20px -14px rgba(23,32,58,.4)}
.proc .ic svg{display:block;width:26px;height:26px;stroke:var(--pr-accent);fill:none;stroke-width:1.9}
.proc h2{font-size:.92rem;font-weight:700;line-height:normal;margin:0 0 5px;letter-spacing:-.01em}
.proc p{font-size:.79rem;color:var(--pr-muted);line-height:1.6;margin:0}
.proc .n{top:-8px;margin-left:14px;width:22px;height:22px;background:var(--pr-accent);font-size:.7rem;font-weight:800;place-items:center}
@media(max-width:760px){
  .proc{flex-direction:column;max-width:320px;align-items:stretch!important;gap:34px}
  .proc .stage:not(:last-child)::before{left:50%;top:calc(100% - 2px);width:2px;height:22px;margin-left:-1px}
  .proc .stage:not(:last-child)::after{left:calc(50% - 6px);top:calc(100% + 26px);
    border-left-color:transparent;border-top-color:var(--pr-arrow)}
}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<ol class="flex w-full max-w-[900px] items-start gap-[42px] max-[760px]:max-w-[320px] max-[760px]:flex-col max-[760px]:items-stretch max-[760px]:gap-[34px]">
  <li class="relative flex-1 px-2.5 text-center not-last:before:absolute not-last:before:top-[31px] not-last:before:left-[calc(100%+2px)] not-last:before:h-0.5 not-last:before:w-[22px] not-last:before:bg-pr-arrow not-last:after:absolute not-last:after:top-[26px] not-last:after:left-[calc(100%+28px)] not-last:after:size-0 not-last:after:border-6 not-last:after:border-transparent not-last:after:border-l-pr-arrow max-[760px]:not-last:before:top-[calc(100%-2px)] max-[760px]:not-last:before:left-1/2 max-[760px]:not-last:before:-ml-px max-[760px]:not-last:before:h-[22px] max-[760px]:not-last:before:w-0.5 max-[760px]:not-last:after:top-[calc(100%+26px)] max-[760px]:not-last:after:left-[calc(50%-6px)] max-[760px]:not-last:after:border-l-transparent max-[760px]:not-last:after:border-t-pr-arrow"><span class="absolute -top-2 left-1/2 ml-3.5 grid size-[22px] place-items-center rounded-full bg-pr-accent text-[.7rem] font-extrabold text-white" aria-hidden="true">1</span>
    <span class="mx-auto mb-[15px] grid size-[62px] place-items-center rounded-[18px] border border-pr-border bg-white shadow-[0_8px_20px_-14px_rgba(23,32,58,.4)]" aria-hidden="true"><svg class="size-[26px] fill-none stroke-pr-accent stroke-[1.9]" viewBox="0 0 24 24"><path d="M4 6h16M4 12h10M4 18h13"/></svg></span>
    <h2 class="mb-[5px] text-[.92rem] font-bold tracking-[-.01em]">Brief</h2><p class="text-[.79rem] leading-[1.6] text-pr-muted">You send references and a rough size. Twenty minutes of your time.</p></li>
  <li class="relative flex-1 px-2.5 text-center not-last:before:absolute not-last:before:top-[31px] not-last:before:left-[calc(100%+2px)] not-last:before:h-0.5 not-last:before:w-[22px] not-last:before:bg-pr-arrow not-last:after:absolute not-last:after:top-[26px] not-last:after:left-[calc(100%+28px)] not-last:after:size-0 not-last:after:border-6 not-last:after:border-transparent not-last:after:border-l-pr-arrow max-[760px]:not-last:before:top-[calc(100%-2px)] max-[760px]:not-last:before:left-1/2 max-[760px]:not-last:before:-ml-px max-[760px]:not-last:before:h-[22px] max-[760px]:not-last:before:w-0.5 max-[760px]:not-last:after:top-[calc(100%+26px)] max-[760px]:not-last:after:left-[calc(50%-6px)] max-[760px]:not-last:after:border-l-transparent max-[760px]:not-last:after:border-t-pr-arrow"><span class="absolute -top-2 left-1/2 ml-3.5 grid size-[22px] place-items-center rounded-full bg-pr-accent text-[.7rem] font-extrabold text-white" aria-hidden="true">2</span>
    <span class="mx-auto mb-[15px] grid size-[62px] place-items-center rounded-[18px] border border-pr-border bg-white shadow-[0_8px_20px_-14px_rgba(23,32,58,.4)]" aria-hidden="true"><svg class="size-[26px] fill-none stroke-pr-accent stroke-[1.9]" viewBox="0 0 24 24"><path d="M4 20h4l10-10-4-4L4 16z"/></svg></span>
    <h2 class="mb-[5px] text-[.92rem] font-bold tracking-[-.01em]">Sketch</h2><p class="text-[.79rem] leading-[1.6] text-pr-muted">Two directions in pencil, so nothing expensive gets built on the wrong idea.</p></li>
  <li class="relative flex-1 px-2.5 text-center not-last:before:absolute not-last:before:top-[31px] not-last:before:left-[calc(100%+2px)] not-last:before:h-0.5 not-last:before:w-[22px] not-last:before:bg-pr-arrow not-last:after:absolute not-last:after:top-[26px] not-last:after:left-[calc(100%+28px)] not-last:after:size-0 not-last:after:border-6 not-last:after:border-transparent not-last:after:border-l-pr-arrow max-[760px]:not-last:before:top-[calc(100%-2px)] max-[760px]:not-last:before:left-1/2 max-[760px]:not-last:before:-ml-px max-[760px]:not-last:before:h-[22px] max-[760px]:not-last:before:w-0.5 max-[760px]:not-last:after:top-[calc(100%+26px)] max-[760px]:not-last:after:left-[calc(50%-6px)] max-[760px]:not-last:after:border-l-transparent max-[760px]:not-last:after:border-t-pr-arrow"><span class="absolute -top-2 left-1/2 ml-3.5 grid size-[22px] place-items-center rounded-full bg-pr-accent text-[.7rem] font-extrabold text-white" aria-hidden="true">3</span>
    <span class="mx-auto mb-[15px] grid size-[62px] place-items-center rounded-[18px] border border-pr-border bg-white shadow-[0_8px_20px_-14px_rgba(23,32,58,.4)]" aria-hidden="true"><svg class="size-[26px] fill-none stroke-pr-accent stroke-[1.9]" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg></span>
    <h2 class="mb-[5px] text-[.92rem] font-bold tracking-[-.01em]">Make</h2><p class="text-[.79rem] leading-[1.6] text-pr-muted">Four to six weeks, with photos at the halfway point.</p></li>
  <li class="relative flex-1 px-2.5 text-center not-last:before:absolute not-last:before:top-[31px] not-last:before:left-[calc(100%+2px)] not-last:before:h-0.5 not-last:before:w-[22px] not-last:before:bg-pr-arrow not-last:after:absolute not-last:after:top-[26px] not-last:after:left-[calc(100%+28px)] not-last:after:size-0 not-last:after:border-6 not-last:after:border-transparent not-last:after:border-l-pr-arrow max-[760px]:not-last:before:top-[calc(100%-2px)] max-[760px]:not-last:before:left-1/2 max-[760px]:not-last:before:-ml-px max-[760px]:not-last:before:h-[22px] max-[760px]:not-last:before:w-0.5 max-[760px]:not-last:after:top-[calc(100%+26px)] max-[760px]:not-last:after:left-[calc(50%-6px)] max-[760px]:not-last:after:border-l-transparent max-[760px]:not-last:after:border-t-pr-arrow"><span class="absolute -top-2 left-1/2 ml-3.5 grid size-[22px] place-items-center rounded-full bg-pr-accent text-[.7rem] font-extrabold text-white" aria-hidden="true">4</span>
    <span class="mx-auto mb-[15px] grid size-[62px] place-items-center rounded-[18px] border border-pr-border bg-white shadow-[0_8px_20px_-14px_rgba(23,32,58,.4)]" aria-hidden="true"><svg class="size-[26px] fill-none stroke-pr-accent stroke-[1.9]" viewBox="0 0 24 24"><path d="M4 8l8-4 8 4v8l-8 4-8-4z"/><path d="M4 8l8 4 8-4M12 12v8"/></svg></span>
    <h2 class="mb-[5px] text-[.92rem] font-bold tracking-[-.01em]">Deliver</h2><p class="text-[.79rem] leading-[1.6] text-pr-muted">Crated, insured, and hung if you are within driving distance.</p></li>
</ol>
CSS
@theme {
  --color-pr-accent: #4f46e5;
  --color-pr-arrow: #c3cbe0;
  --color-pr-border: #e3e8f2;
  --color-pr-muted: #5f6a86;
}

About this set

A four-stage process strip with an icon tile, a number badge, a short heading and a sentence per stage, joined by small CSS arrows. The demo explains how a commission works, from brief and sketch to make and deliver, and the same layout suits a how-it-works section on a service page, a hiring process or an onboarding overview. Each stage has a 62 pixel rounded white tile with a soft shadow holding a line icon, and an indigo badge with the step number sits on its top right corner. The stages are an ordered list laid out with flexbox and a 42 pixel gap, and the arrows live in that gap: each stage except the last draws a short line with ::before and a triangle with ::after, so the list contains nothing but list items. Below 760 pixels the list becomes a single column and the arrows turn to point downwards. Icons and number badges are hidden from screen readers because the ordered list already gives the numbering. The Bootstrap version uses its flex and list utilities with the arrows in a small custom block, and the Tailwind version draws the arrows with not-last:before: and not-last:after: utilities.

What’s included

  • Four stages with an icon tile, number badge, heading and text
  • Connector arrows drawn with pseudo-elements in the flex gap
  • Clean ordered list with no decorative list items
  • Stacks into one column with downward arrows below 760px
  • Inline SVG icons, no icon font

Accessibility

The stages are an ordered list, so screen readers announce the count and position; the visible number badges and icons are aria-hidden to avoid repeating it. Headings and body text meet 4.5:1 contrast, and the arrows are pure CSS decoration. Nothing animates.

Customise it

Change --pr-accent for the icons and badges, --pr-arrow for the connectors and --pr-muted for the body text on .proc (plain CSS and Bootstrap), or the --color-pr-* theme colours in Tailwind. The 760px media query controls when the strip stacks.