Open demo

CSS code

HTML
<div><span class="lbl">Filled arrows</span>
<nav class="steps" aria-label="Breadcrumb">
  <ol>
    <li><a href="#">Home</a></li>
    <li><a href="#">Courses</a></li>
    <li><a href="#">Design</a></li>
    <li aria-current="page">Typography</li>
  </ol>
</nav></div>

<div><span class="lbl">Graduated tint</span>
<nav class="steps steps-grad" aria-label="Breadcrumb">
  <ol>
    <li><a href="#">Atlas</a></li>
    <li><a href="#">Europe</a></li>
    <li><a href="#">Norway</a></li>
    <li aria-current="page">Lofoten</li>
  </ol>
</nav></div>

<div><span class="lbl">Bordered path bar</span>
<nav class="pathbar" aria-label="Breadcrumb">
  <ol>
    <li><a href="#">Acme</a></li>
    <li><a href="#">Teams</a></li>
    <li><a href="#">Platform</a></li>
    <li aria-current="page">Alerts</li>
  </ol>
</nav></div>
CSS
/* Arrow steps: each li paints its arrow on ::before with clip-path, behind the text (z-index -1 inside
   the isolated list). The link is stretched over the whole arrow with a::after. */
.steps{--st-bg:#e0e7ff;--st-fg:#3730a3;--st-hover:#c7d2fe;--st-cur-bg:#4f46e5;--st-cur-fg:#fff;--st-tip:12px;--st-gap:3px;
  font-size:.8125rem;font-weight:600;line-height:1.25}
.steps ol{display:flex;flex-wrap:wrap;row-gap:6px;margin:0;padding:0;list-style:none;isolation:isolate}
.steps li{position:relative;color:var(--st-fg);padding:.6rem calc(var(--st-tip) + .4rem) .6rem calc(var(--st-tip) + .55rem)}
.steps li+li{margin-left:calc(var(--st-gap) - var(--st-tip))}
.steps li:first-child{padding-left:.9rem}
.steps li::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--st-bg);transition:background-color .15s;
  clip-path:polygon(0 0,calc(100% - var(--st-tip)) 0,100% 50%,calc(100% - var(--st-tip)) 100%,0 100%,var(--st-tip) 50%)}
.steps li:first-child::before{clip-path:polygon(0 0,calc(100% - var(--st-tip)) 0,100% 50%,calc(100% - var(--st-tip)) 100%,0 100%);border-radius:8px 0 0 8px}
.steps li:not([aria-current]):hover::before{background:var(--st-hover)}
.steps [aria-current="page"]{color:var(--st-cur-fg)}
.steps [aria-current="page"]::before{background:var(--st-cur-bg)}
.steps a{color:inherit;text-decoration:none;border-radius:3px}
.steps a::after{content:"";position:absolute;inset:0}
.steps a:focus-visible{outline:2px solid currentColor;outline-offset:3px}
/* graduated: every level a step darker */
.steps-grad{--st-fg:#134e4a;--st-bg:#ccfbf1;--st-hover:#a7f3e4;--st-cur-bg:#0f766e;--st-tip:10px;--st-gap:2px;
  font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}
.steps-grad li:nth-child(2){--st-bg:#99f6e4;--st-hover:#7eeed8}
.steps-grad li:nth-child(3){--st-bg:#5eead4;--st-hover:#48dcc4}
/* bordered path bar: one outlined bar, levels split by a tall chevron line */
.pathbar{--pb-line:#d4dae4;--pb-fg:#475569;--pb-hover:#f1f5f9;--pb-cur-bg:#eef2ff;--pb-cur-fg:#3730a3;--pb-h:44px;
  font-size:.875rem;line-height:1.25}
.pathbar ol{display:inline-flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;background:#fff;
  border:1px solid var(--pb-line);border-radius:10px;overflow:hidden;isolation:isolate}
.pathbar li{position:relative;display:flex;align-items:center;height:var(--pb-h);padding:0 1.5rem 0 2rem;color:var(--pb-fg);transition:background-color .15s}
.pathbar li:first-child{padding-left:1rem}
.pathbar li:last-child{padding-right:1.1rem}
.pathbar li+li::before{content:"";position:absolute;z-index:1;left:0;top:50%;width:calc(var(--pb-h) * .7071);aspect-ratio:1;
  background:#fff;border:solid var(--pb-line);border-width:1px 1px 0 0;transform:translate(-50%,-50%) rotate(45deg)}
.pathbar li:not([aria-current]):hover{background:var(--pb-hover)}
.pathbar li:not([aria-current]):hover+li::before{background:var(--pb-hover)}
.pathbar [aria-current="page"]{background:var(--pb-cur-bg);color:var(--pb-cur-fg);font-weight:600}
.pathbar a{color:inherit;text-decoration:none;border-radius:3px}
.pathbar a::after{content:"";position:absolute;inset:0}
.pathbar a:focus-visible{outline:2px solid #4338ca;outline-offset:3px}
/* narrow screens: tighter arrows so four levels fit on one line */
@media (max-width:420px){
  .steps{--st-tip:10px;font-size:.75rem}
  .steps li{padding-right:calc(var(--st-tip) + .25rem);padding-left:calc(var(--st-tip) + .4rem)}
  .steps li:first-child{padding-left:.7rem}
  .steps-grad{font-size:.6875rem;letter-spacing:.03em}
  .pathbar{--pb-h:38px;font-size:.8125rem}
  .pathbar li{padding:0 1.3rem 0 1.55rem}
  .pathbar li:first-child{padding-left:.75rem}
  .pathbar li:last-child{padding-right:.8rem}
}
@media (prefers-reduced-motion:reduce){.steps li::before,.pathbar li{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Filled arrows</span>
<nav class="steps" aria-label="Breadcrumb">
  <ol class="breadcrumb">
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Home</a></li>
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Courses</a></li>
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Design</a></li>
    <li class="breadcrumb-item active" aria-current="page">Typography</li>
  </ol>
</nav></div>

<div><span class="lbl">Graduated tint</span>
<nav class="steps steps-grad" aria-label="Breadcrumb">
  <ol class="breadcrumb">
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Atlas</a></li>
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Europe</a></li>
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Norway</a></li>
    <li class="breadcrumb-item active" aria-current="page">Lofoten</li>
  </ol>
</nav></div>

<div><span class="lbl">Bordered path bar</span>
<nav class="pathbar" aria-label="Breadcrumb">
  <ol class="breadcrumb">
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Acme</a></li>
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Teams</a></li>
    <li class="breadcrumb-item"><a href="#" class="stretched-link">Platform</a></li>
    <li class="breadcrumb-item active" aria-current="page">Alerts</li>
  </ol>
</nav></div>
CSS
/* Bootstrap .breadcrumb as arrow steps: each .breadcrumb-item paints its arrow on ::before with clip-path,
   behind the text. Bootstrap's divider is replaced by the shape, and .stretched-link makes the whole arrow clickable. */
.steps{--st-bg:#e0e7ff;--st-fg:#3730a3;--st-hover:#c7d2fe;--st-cur-bg:#4f46e5;--st-cur-fg:#fff;--st-tip:12px;--st-gap:3px;
  font-size:.8125rem;font-weight:600;line-height:1.25}
.steps .breadcrumb,.pathbar .breadcrumb{--bs-breadcrumb-margin-bottom:0;--bs-breadcrumb-item-padding-x:0}
.steps .breadcrumb{display:flex;flex-wrap:wrap;row-gap:6px;margin:0;padding:0;list-style:none;isolation:isolate}
.steps .breadcrumb-item{position:relative;color:var(--st-fg);padding:.6rem calc(var(--st-tip) + .4rem) .6rem calc(var(--st-tip) + .55rem)}
.steps .breadcrumb-item+.breadcrumb-item{margin-left:calc(var(--st-gap) - var(--st-tip))}
.steps .breadcrumb-item:first-child{padding-left:.9rem}
.steps .breadcrumb-item::before{content:"";float:none;padding:0;position:absolute;inset:0;z-index:-1;background:var(--st-bg);transition:background-color .15s;
  clip-path:polygon(0 0,calc(100% - var(--st-tip)) 0,100% 50%,calc(100% - var(--st-tip)) 100%,0 100%,var(--st-tip) 50%)}
.steps .breadcrumb-item:first-child::before{clip-path:polygon(0 0,calc(100% - var(--st-tip)) 0,100% 50%,calc(100% - var(--st-tip)) 100%,0 100%);border-radius:8px 0 0 8px}
.steps .breadcrumb-item:not(.active):hover::before{background:var(--st-hover)}
.steps .breadcrumb-item.active{color:var(--st-cur-fg)}
.steps .breadcrumb-item.active::before{background:var(--st-cur-bg)}
.steps a{color:inherit;text-decoration:none;border-radius:3px}
.steps a:focus-visible{outline:2px solid currentColor;outline-offset:3px}
/* graduated: every level a step darker */
.steps-grad{--st-fg:#134e4a;--st-bg:#ccfbf1;--st-hover:#a7f3e4;--st-cur-bg:#0f766e;--st-tip:10px;--st-gap:2px;
  font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}
.steps-grad .breadcrumb-item:nth-child(2){--st-bg:#99f6e4;--st-hover:#7eeed8}
.steps-grad .breadcrumb-item:nth-child(3){--st-bg:#5eead4;--st-hover:#48dcc4}
/* bordered path bar: one outlined bar, levels split by a tall chevron line */
.pathbar{--pb-line:#d4dae4;--pb-fg:#475569;--pb-hover:#f1f5f9;--pb-cur-bg:#eef2ff;--pb-cur-fg:#3730a3;--pb-h:44px;
  font-size:.875rem;line-height:1.25}
.pathbar .breadcrumb{display:inline-flex;flex-wrap:wrap;margin:0;padding:0;list-style:none;background:#fff;
  border:1px solid var(--pb-line);border-radius:10px;overflow:hidden;isolation:isolate}
.pathbar .breadcrumb-item{position:relative;display:flex;align-items:center;height:var(--pb-h);padding:0 1.5rem 0 2rem;color:var(--pb-fg);transition:background-color .15s}
.pathbar .breadcrumb-item:first-child{padding-left:1rem}
.pathbar .breadcrumb-item:last-child{padding-right:1.1rem}
.pathbar .breadcrumb-item+.breadcrumb-item::before{float:none;padding:0;content:"";position:absolute;z-index:1;left:0;top:50%;width:calc(var(--pb-h) * .7071);aspect-ratio:1;
  background:#fff;border:solid var(--pb-line);border-width:1px 1px 0 0;transform:translate(-50%,-50%) rotate(45deg)}
.pathbar .breadcrumb-item:not(.active):hover{background:var(--pb-hover)}
.pathbar .breadcrumb-item:not(.active):hover+.breadcrumb-item::before{background:var(--pb-hover)}
.pathbar .breadcrumb-item.active{background:var(--pb-cur-bg);color:var(--pb-cur-fg);font-weight:600}
.pathbar a{color:inherit;text-decoration:none;border-radius:3px}
.pathbar a:focus-visible{outline:2px solid #4338ca;outline-offset:3px}
/* narrow screens: tighter arrows so four levels fit on one line */
@media (max-width:420px){
  .steps{--st-tip:10px;font-size:.75rem}
  .steps .breadcrumb-item{padding-right:calc(var(--st-tip) + .25rem);padding-left:calc(var(--st-tip) + .4rem)}
  .steps .breadcrumb-item:first-child{padding-left:.7rem}
  .steps-grad{font-size:.6875rem;letter-spacing:.03em}
  .pathbar{--pb-h:38px;font-size:.8125rem}
  .pathbar .breadcrumb-item{padding:0 1.3rem 0 1.55rem}
  .pathbar .breadcrumb-item:first-child{padding-left:.75rem}
  .pathbar .breadcrumb-item:last-child{padding-right:.8rem}
}
@media (prefers-reduced-motion:reduce){.steps .breadcrumb-item::before,.pathbar .breadcrumb-item{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#5b6477] uppercase">Filled arrows</span>
<nav aria-label="Breadcrumb" class="[--tip:12px] text-[.8125rem] leading-[1.25] font-semibold max-[420px]:[--tip:10px] max-[420px]:text-xs">
  <ol class="isolate flex flex-wrap gap-y-1.5">
    <li class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[.9rem] max-[420px]:pl-[.7rem] before:absolute before:inset-0 before:-z-10 before:clip-arrow-first before:rounded-l-lg before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-[#3730a3] before:bg-[#e0e7ff] hover:before:bg-[#c7d2fe]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-current">Home</a></li>
    <li class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[calc(var(--tip)+.55rem)] ml-[calc(3px_-_var(--tip))] max-[420px]:pl-[calc(var(--tip)+.4rem)] before:absolute before:inset-0 before:-z-10 before:clip-arrow before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-[#3730a3] before:bg-[#e0e7ff] hover:before:bg-[#c7d2fe]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-current">Courses</a></li>
    <li class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[calc(var(--tip)+.55rem)] ml-[calc(3px_-_var(--tip))] max-[420px]:pl-[calc(var(--tip)+.4rem)] before:absolute before:inset-0 before:-z-10 before:clip-arrow before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-[#3730a3] before:bg-[#e0e7ff] hover:before:bg-[#c7d2fe]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-current">Design</a></li>
    <li aria-current="page" class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[calc(var(--tip)+.55rem)] ml-[calc(3px_-_var(--tip))] max-[420px]:pl-[calc(var(--tip)+.4rem)] before:absolute before:inset-0 before:-z-10 before:clip-arrow before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-white before:bg-[#4f46e5]">Typography</li>
  </ol>
</nav></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#5b6477] uppercase">Graduated tint</span>
<nav aria-label="Breadcrumb" class="[--tip:10px] text-xs leading-[1.25] font-semibold tracking-[.06em] uppercase max-[420px]:text-[.6875rem] max-[420px]:tracking-[.03em]">
  <ol class="isolate flex flex-wrap gap-y-1.5">
    <li class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[.9rem] max-[420px]:pl-[.7rem] before:absolute before:inset-0 before:-z-10 before:clip-arrow-first before:rounded-l-lg before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-[#134e4a] before:bg-[#ccfbf1] hover:before:bg-[#a7f3e4]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-current">Atlas</a></li>
    <li class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[calc(var(--tip)+.55rem)] ml-[calc(2px_-_var(--tip))] max-[420px]:pl-[calc(var(--tip)+.4rem)] before:absolute before:inset-0 before:-z-10 before:clip-arrow before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-[#134e4a] before:bg-[#99f6e4] hover:before:bg-[#7eeed8]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-current">Europe</a></li>
    <li class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[calc(var(--tip)+.55rem)] ml-[calc(2px_-_var(--tip))] max-[420px]:pl-[calc(var(--tip)+.4rem)] before:absolute before:inset-0 before:-z-10 before:clip-arrow before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-[#134e4a] before:bg-[#5eead4] hover:before:bg-[#48dcc4]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-current">Norway</a></li>
    <li aria-current="page" class="relative py-[.6rem] pr-[calc(var(--tip)+.4rem)] max-[420px]:pr-[calc(var(--tip)+.25rem)] pl-[calc(var(--tip)+.55rem)] ml-[calc(2px_-_var(--tip))] max-[420px]:pl-[calc(var(--tip)+.4rem)] before:absolute before:inset-0 before:-z-10 before:clip-arrow before:transition-[color,background-color,border-color] motion-reduce:before:transition-none text-white before:bg-[#0f766e]">Lofoten</li>
  </ol>
</nav></div>

<div><span class="mb-3 block text-[.72rem] tracking-[.12em] text-[#5b6477] uppercase">Bordered path bar</span>
<nav aria-label="Breadcrumb" class="[--pb-h:44px] text-sm leading-[1.25] max-[420px]:[--pb-h:38px] max-[420px]:text-[.8125rem]">
  <ol class="isolate inline-flex flex-wrap overflow-hidden rounded-[10px] border border-[#d4dae4] bg-white">
    <li class="relative flex h-(--pb-h) items-center pr-6 pl-4 max-[420px]:pr-[1.3rem] max-[420px]:pl-3 text-[#475569] transition-[color,background-color,border-color] hover:bg-[#f1f5f9] motion-reduce:transition-none"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#4338ca]">Acme</a></li>
    <li class="relative flex h-(--pb-h) items-center pl-8 pr-6 max-[420px]:pl-[1.55rem] max-[420px]:pr-[1.3rem] text-[#475569] transition-[color,background-color,border-color] hover:bg-[#f1f5f9] motion-reduce:transition-none before:absolute before:top-1/2 before:left-0 before:z-1 before:aspect-square before:w-[calc(var(--pb-h)*.7071)] before:-translate-1/2 before:rotate-45 before:border-t before:border-r before:border-[#d4dae4] before:bg-white [li:not([aria-current]):hover+&]:before:bg-[#f1f5f9]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#4338ca]">Teams</a></li>
    <li class="relative flex h-(--pb-h) items-center pl-8 pr-6 max-[420px]:pl-[1.55rem] max-[420px]:pr-[1.3rem] text-[#475569] transition-[color,background-color,border-color] hover:bg-[#f1f5f9] motion-reduce:transition-none before:absolute before:top-1/2 before:left-0 before:z-1 before:aspect-square before:w-[calc(var(--pb-h)*.7071)] before:-translate-1/2 before:rotate-45 before:border-t before:border-r before:border-[#d4dae4] before:bg-white [li:not([aria-current]):hover+&]:before:bg-[#f1f5f9]"><a href="#" class="rounded-[3px] text-inherit no-underline after:absolute after:inset-0 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#4338ca]">Platform</a></li>
    <li aria-current="page" class="relative flex h-(--pb-h) items-center pr-[1.1rem] pl-8 max-[420px]:pr-[.8rem] max-[420px]:pl-[1.55rem] bg-[#eef2ff] font-semibold text-[#3730a3] before:absolute before:top-1/2 before:left-0 before:z-1 before:aspect-square before:w-[calc(var(--pb-h)*.7071)] before:-translate-1/2 before:rotate-45 before:border-t before:border-r before:border-[#d4dae4] before:bg-white [li:not([aria-current]):hover+&]:before:bg-[#f1f5f9]">Alerts</li>
  </ol>
</nav></div>
CSS
/* Arrow shapes for li::before. --tip (set on the nav) is the depth of the point and the notch. */
@utility clip-arrow { clip-path: polygon(0 0, calc(100% - var(--tip)) 0, 100% 50%, calc(100% - var(--tip)) 100%, 0 100%, var(--tip) 50%); }
@utility clip-arrow-first { clip-path: polygon(0 0, calc(100% - var(--tip)) 0, 100% 50%, calc(100% - var(--tip)) 100%, 0 100%); }

About this set

Three breadcrumbs where every level is a shape rather than a word between separators. Filled arrows are indigo chevron blocks that nest into each other, with the current page in solid indigo. Graduated tint uses teal blocks that darken one step per level, so depth reads at a glance, with compact uppercase labels. The bordered path bar is a single outlined bar split by tall chevron lines, with the current level on a pale indigo tint, the look of file managers and cloud consoles. Use the arrows for course or catalogue hierarchies that deserve visual weight, and the path bar in admin screens where it should blend with toolbars. Each arrow is painted on li::before with clip-path, behind the text, so focus outlines on the links are never clipped, and the link is stretched over the whole arrow to make the full shape clickable. Below 420px the arrows tighten so four levels still fit on one line. The Bootstrap version replaces the .breadcrumb divider with the same shapes and uses .stretched-link.

What’s included

  • Filled arrows, graduated tint and bordered path bar variants
  • Arrows drawn with clip-path on a pseudo-element, so focus rings stay visible
  • Whole arrow is clickable through a stretched link
  • Narrow-screen sizing keeps four levels on one row at 375px
  • Hover state darkens the arrow; current page has its own fill

Accessibility

Each variant is a nav with aria-label="Breadcrumb" and an ordered list, with aria-current="page" on the last level. The arrows and chevron lines are pseudo-elements with no text, so they are not announced. Links show a 2px outline in the text colour when focused by keyboard, and background transitions are removed under prefers-reduced-motion. White text on the current step is at least 5.4:1.

Customise it

Change --st-bg, --st-fg, --st-hover, --st-cur-bg and --st-tip (arrow depth) on .steps, or the --pb-* variables on .pathbar; the Bootstrap version uses the same variables. In Tailwind set [--tip:12px] on the nav and change the before:bg- colour classes per level.