39 CSS Breadcrumbs22 / 39
Developer Docs Breadcrumb with One-Click Path Copy to Clipboard
Terminal-inspired breadcrumb for developer documentation sites (Stripe, Vercel, Cloudflare, Docker, MDN). Monospace typography with slash separators and a one-click copy button that pushes the full path to the clipboard so devs can drop it straight into Slack, Linear, or a PR.
Published
The code
<section class="bc-22" aria-label="Developer docs breadcrumb with path copy demo">
<nav class="bc-22__nav" aria-label="Documentation breadcrumb">
<ol class="bc-22__list">
<li><a href="#">docs</a></li>
<li><a href="#">api</a></li>
<li><a href="#">authentication</a></li>
<li><a aria-current="page" href="#">oauth2</a></li>
</ol>
<button type="button" class="bc-22__copy" aria-label="Copy path to clipboard" data-cf-track="copy_path_click">
<svg class="bc-22__icon bc-22__icon--copy" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
<svg class="bc-22__icon bc-22__icon--check" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="m5 12 5 5L20 7"/></svg>
</button>
<span class="bc-22__sr" role="status" aria-live="polite" aria-atomic="true"></span>
</nav>
</section><section class="bc-22" aria-label="Developer docs breadcrumb with path copy demo">
<nav class="bc-22__nav" aria-label="Documentation breadcrumb">
<ol class="bc-22__list">
<li><a href="#">docs</a></li>
<li><a href="#">api</a></li>
<li><a href="#">authentication</a></li>
<li><a aria-current="page" href="#">oauth2</a></li>
</ol>
<button type="button" class="bc-22__copy" aria-label="Copy path to clipboard" data-cf-track="copy_path_click">
<svg class="bc-22__icon bc-22__icon--copy" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
<svg class="bc-22__icon bc-22__icon--check" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="m5 12 5 5L20 7"/></svg>
</button>
<span class="bc-22__sr" role="status" aria-live="polite" aria-atomic="true"></span>
</nav>
</section>.bc-22 {
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 2rem 1.25rem;
background: radial-gradient(1200px 600px at 50% -10%, oklch(0.28 0.05 265 / 0.55), transparent 60%), oklch(0.16 0.02 260);
font-family: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
color: oklch(0.82 0.02 260);
--bc18-accent: oklch(0.78 0.17 300);
--bc18-muted: oklch(0.58 0.02 260);
--bc18-sep: oklch(0.42 0.02 260);
--bc18-surface: oklch(0.21 0.02 260);
--bc18-border: oklch(0.32 0.02 260 / 0.6);
}
.bc-22 *,
.bc-22 *::before,
.bc-22 *::after {
box-sizing: border-box;
}
.bc-22__nav {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.5rem 0.5rem 1rem;
background: var(--bc18-surface);
border: 1px solid var(--bc18-border);
border-radius: 12px;
box-shadow: 0 1px 0 oklch(1 0 0 / 0.04) inset, 0 10px 30px -12px oklch(0 0 0 / 0.6);
font-size: 0.9375rem;
line-height: 1.2;
max-width: 100%;
overflow-x: auto;
scrollbar-width: thin;
scrollbar-color: var(--bc18-border) transparent;
}
.bc-22__list {
list-style: none;
margin: 0;
padding: 0;
display: inline-flex;
align-items: center;
flex-wrap: nowrap;
gap: 0.25rem;
}
.bc-22__list li {
display: inline-flex;
align-items: center;
gap: 0.25rem;
white-space: nowrap;
}
.bc-22__list li + li::before {
content: "/";
color: var(--bc18-sep);
padding: 0 0.25rem;
user-select: none;
}
.bc-22__list a {
color: var(--bc18-muted);
text-decoration: none;
padding: 0.375rem 0.5rem;
border-radius: 6px;
transition: color 160ms ease, background-color 160ms ease;
}
.bc-22__list a:hover {
color: oklch(0.92 0.02 260);
background: color-mix(in oklch, var(--bc18-accent) 8%, transparent);
}
.bc-22__list a[aria-current="page"] {
color: var(--bc18-accent);
background: color-mix(in oklch, var(--bc18-accent) 12%, transparent);
font-weight: 600;
cursor: default;
}
.bc-22__list a:focus-visible,
.bc-22__copy:focus-visible {
outline: 2px solid var(--bc18-accent);
outline-offset: 2px;
border-radius: 6px;
}
.bc-22__copy {
appearance: none;
border: 1px solid var(--bc18-border);
background: color-mix(in oklch, var(--bc18-surface) 70%, oklch(0.28 0.02 260));
color: oklch(0.82 0.02 260);
min-width: 44px;
min-height: 44px;
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
position: relative;
transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease, transform 160ms ease;
flex-shrink: 0;
}
.bc-22__copy:hover {
color: oklch(0.95 0.02 260);
border-color: color-mix(in oklch, var(--bc18-accent) 40%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 10%, var(--bc18-surface));
}
.bc-22__copy:active {
transform: scale(0.96);
}
.bc-22__icon {
width: 18px;
height: 18px;
position: absolute;
inset: 0;
margin: auto;
transition: opacity 180ms ease, transform 180ms ease;
}
.bc-22__icon--check {
color: var(--bc18-accent);
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--copy {
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--check {
opacity: 1;
transform: scale(1);
}
.bc-22__copy.is-copied {
border-color: color-mix(in oklch, var(--bc18-accent) 60%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 15%, var(--bc18-surface));
}
.bc-22__sr {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (prefers-reduced-motion: reduce) {
.bc-22__list a,
.bc-22__copy,
.bc-22__icon {
transition: none;
}
.bc-22__copy:active {
transform: none;
}
}
@media (max-width: 480px) {
.bc-22__nav {
font-size: 0.8125rem;
padding-left: 0.75rem;
}
}.bc-22 {
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 2rem 1.25rem;
background: radial-gradient(1200px 600px at 50% -10%, oklch(0.28 0.05 265 / 0.55), transparent 60%), oklch(0.16 0.02 260);
font-family: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
color: oklch(0.82 0.02 260);
--bc18-accent: oklch(0.78 0.17 300);
--bc18-muted: oklch(0.58 0.02 260);
--bc18-sep: oklch(0.42 0.02 260);
--bc18-surface: oklch(0.21 0.02 260);
--bc18-border: oklch(0.32 0.02 260 / 0.6);
}
.bc-22 *,
.bc-22 *::before,
.bc-22 *::after {
box-sizing: border-box;
}
.bc-22__nav {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.5rem 0.5rem 1rem;
background: var(--bc18-surface);
border: 1px solid var(--bc18-border);
border-radius: 12px;
box-shadow: 0 1px 0 oklch(1 0 0 / 0.04) inset, 0 10px 30px -12px oklch(0 0 0 / 0.6);
font-size: 0.9375rem;
line-height: 1.2;
max-width: 100%;
overflow-x: auto;
scrollbar-width: thin;
scrollbar-color: var(--bc18-border) transparent;
}
.bc-22__list {
list-style: none;
margin: 0;
padding: 0;
display: inline-flex;
align-items: center;
flex-wrap: nowrap;
gap: 0.25rem;
}
.bc-22__list li {
display: inline-flex;
align-items: center;
gap: 0.25rem;
white-space: nowrap;
}
.bc-22__list li + li::before {
content: "/";
color: var(--bc18-sep);
padding: 0 0.25rem;
user-select: none;
}
.bc-22__list a {
color: var(--bc18-muted);
text-decoration: none;
padding: 0.375rem 0.5rem;
border-radius: 6px;
transition: color 160ms ease, background-color 160ms ease;
}
.bc-22__list a:hover {
color: oklch(0.92 0.02 260);
background: color-mix(in oklch, var(--bc18-accent) 8%, transparent);
}
.bc-22__list a[aria-current="page"] {
color: var(--bc18-accent);
background: color-mix(in oklch, var(--bc18-accent) 12%, transparent);
font-weight: 600;
cursor: default;
}
.bc-22__list a:focus-visible,
.bc-22__copy:focus-visible {
outline: 2px solid var(--bc18-accent);
outline-offset: 2px;
border-radius: 6px;
}
.bc-22__copy {
appearance: none;
border: 1px solid var(--bc18-border);
background: color-mix(in oklch, var(--bc18-surface) 70%, oklch(0.28 0.02 260));
color: oklch(0.82 0.02 260);
min-width: 44px;
min-height: 44px;
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
position: relative;
transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease, transform 160ms ease;
flex-shrink: 0;
}
.bc-22__copy:hover {
color: oklch(0.95 0.02 260);
border-color: color-mix(in oklch, var(--bc18-accent) 40%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 10%, var(--bc18-surface));
}
.bc-22__copy:active {
transform: scale(0.96);
}
.bc-22__icon {
width: 18px;
height: 18px;
position: absolute;
inset: 0;
margin: auto;
transition: opacity 180ms ease, transform 180ms ease;
}
.bc-22__icon--check {
color: var(--bc18-accent);
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--copy {
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--check {
opacity: 1;
transform: scale(1);
}
.bc-22__copy.is-copied {
border-color: color-mix(in oklch, var(--bc18-accent) 60%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 15%, var(--bc18-surface));
}
.bc-22__sr {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (prefers-reduced-motion: reduce) {
.bc-22__list a,
.bc-22__copy,
.bc-22__icon {
transition: none;
}
.bc-22__copy:active {
transform: none;
}
}
@media (max-width: 480px) {
.bc-22__nav {
font-size: 0.8125rem;
padding-left: 0.75rem;
}
}(() => {
const btn = document.querySelector('.bc-22__copy');
if (!btn) return;
const live = document.querySelector('.bc-22 .bc-22__sr');
const path = 'docs/api/authentication/oauth2';
btn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(path);
btn.classList.add('is-copied');
if (live) live.textContent = 'Path copied to clipboard';
setTimeout(() => {
btn.classList.remove('is-copied');
if (live) live.textContent = '';
}, 1200);
} catch (err) {
// Clipboard API can fail on http:// or if permission denied — fail silently in demo.
}
});
})();(() => {
const btn = document.querySelector('.bc-22__copy');
if (!btn) return;
const live = document.querySelector('.bc-22 .bc-22__sr');
const path = 'docs/api/authentication/oauth2';
btn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(path);
btn.classList.add('is-copied');
if (live) live.textContent = 'Path copied to clipboard';
setTimeout(() => {
btn.classList.remove('is-copied');
if (live) live.textContent = '';
}, 1200);
} catch (err) {
// Clipboard API can fail on http:// or if permission denied — fail silently in demo.
}
});
})();Here's a working CSS Breadcrumb from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Developer Docs Breadcrumb with One-Click Path Copy to Clipboard
Source: https://codefronts.com/navigation/css-breadcrumbs/copy-path/
Terminal-inspired breadcrumb for developer documentation sites (Stripe, Vercel, Cloudflare, Docker, MDN). Monospace typography with slash separators and a one-click copy button that pushes the full path to the clipboard so devs can drop it straight into Slack, Linear, or a PR.
## HTML
```html
<section class="bc-22" aria-label="Developer docs breadcrumb with path copy demo">
<nav class="bc-22__nav" aria-label="Documentation breadcrumb">
<ol class="bc-22__list">
<li><a href="#">docs</a></li>
<li><a href="#">api</a></li>
<li><a href="#">authentication</a></li>
<li><a aria-current="page" href="#">oauth2</a></li>
</ol>
<button type="button" class="bc-22__copy" aria-label="Copy path to clipboard" data-cf-track="copy_path_click">
<svg class="bc-22__icon bc-22__icon--copy" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
<svg class="bc-22__icon bc-22__icon--check" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="m5 12 5 5L20 7"/></svg>
</button>
<span class="bc-22__sr" role="status" aria-live="polite" aria-atomic="true"></span>
</nav>
</section>
```
## CSS
```css
.bc-22 {
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 2rem 1.25rem;
background: radial-gradient(1200px 600px at 50% -10%, oklch(0.28 0.05 265 / 0.55), transparent 60%), oklch(0.16 0.02 260);
font-family: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
color: oklch(0.82 0.02 260);
--bc18-accent: oklch(0.78 0.17 300);
--bc18-muted: oklch(0.58 0.02 260);
--bc18-sep: oklch(0.42 0.02 260);
--bc18-surface: oklch(0.21 0.02 260);
--bc18-border: oklch(0.32 0.02 260 / 0.6);
}
.bc-22 *,
.bc-22 *::before,
.bc-22 *::after {
box-sizing: border-box;
}
.bc-22__nav {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.5rem 0.5rem 1rem;
background: var(--bc18-surface);
border: 1px solid var(--bc18-border);
border-radius: 12px;
box-shadow: 0 1px 0 oklch(1 0 0 / 0.04) inset, 0 10px 30px -12px oklch(0 0 0 / 0.6);
font-size: 0.9375rem;
line-height: 1.2;
max-width: 100%;
overflow-x: auto;
scrollbar-width: thin;
scrollbar-color: var(--bc18-border) transparent;
}
.bc-22__list {
list-style: none;
margin: 0;
padding: 0;
display: inline-flex;
align-items: center;
flex-wrap: nowrap;
gap: 0.25rem;
}
.bc-22__list li {
display: inline-flex;
align-items: center;
gap: 0.25rem;
white-space: nowrap;
}
.bc-22__list li + li::before {
content: "/";
color: var(--bc18-sep);
padding: 0 0.25rem;
user-select: none;
}
.bc-22__list a {
color: var(--bc18-muted);
text-decoration: none;
padding: 0.375rem 0.5rem;
border-radius: 6px;
transition: color 160ms ease, background-color 160ms ease;
}
.bc-22__list a:hover {
color: oklch(0.92 0.02 260);
background: color-mix(in oklch, var(--bc18-accent) 8%, transparent);
}
.bc-22__list a[aria-current="page"] {
color: var(--bc18-accent);
background: color-mix(in oklch, var(--bc18-accent) 12%, transparent);
font-weight: 600;
cursor: default;
}
.bc-22__list a:focus-visible,
.bc-22__copy:focus-visible {
outline: 2px solid var(--bc18-accent);
outline-offset: 2px;
border-radius: 6px;
}
.bc-22__copy {
appearance: none;
border: 1px solid var(--bc18-border);
background: color-mix(in oklch, var(--bc18-surface) 70%, oklch(0.28 0.02 260));
color: oklch(0.82 0.02 260);
min-width: 44px;
min-height: 44px;
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
position: relative;
transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease, transform 160ms ease;
flex-shrink: 0;
}
.bc-22__copy:hover {
color: oklch(0.95 0.02 260);
border-color: color-mix(in oklch, var(--bc18-accent) 40%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 10%, var(--bc18-surface));
}
.bc-22__copy:active {
transform: scale(0.96);
}
.bc-22__icon {
width: 18px;
height: 18px;
position: absolute;
inset: 0;
margin: auto;
transition: opacity 180ms ease, transform 180ms ease;
}
.bc-22__icon--check {
color: var(--bc18-accent);
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--copy {
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--check {
opacity: 1;
transform: scale(1);
}
.bc-22__copy.is-copied {
border-color: color-mix(in oklch, var(--bc18-accent) 60%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 15%, var(--bc18-surface));
}
.bc-22__sr {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (prefers-reduced-motion: reduce) {
.bc-22__list a,
.bc-22__copy,
.bc-22__icon {
transition: none;
}
.bc-22__copy:active {
transform: none;
}
}
@media (max-width: 480px) {
.bc-22__nav {
font-size: 0.8125rem;
padding-left: 0.75rem;
}
}
```
## JavaScript
```js
(() => {
const btn = document.querySelector('.bc-22__copy');
if (!btn) return;
const live = document.querySelector('.bc-22 .bc-22__sr');
const path = 'docs/api/authentication/oauth2';
btn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(path);
btn.classList.add('is-copied');
if (live) live.textContent = 'Path copied to clipboard';
setTimeout(() => {
btn.classList.remove('is-copied');
if (live) live.textContent = '';
}, 1200);
} catch (err) {
// Clipboard API can fail on http:// or if permission denied — fail silently in demo.
}
});
})();
```Here's a working CSS Breadcrumb from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Developer Docs Breadcrumb with One-Click Path Copy to Clipboard
Source: https://codefronts.com/navigation/css-breadcrumbs/copy-path/
Terminal-inspired breadcrumb for developer documentation sites (Stripe, Vercel, Cloudflare, Docker, MDN). Monospace typography with slash separators and a one-click copy button that pushes the full path to the clipboard so devs can drop it straight into Slack, Linear, or a PR.
## HTML
```html
<section class="bc-22" aria-label="Developer docs breadcrumb with path copy demo">
<nav class="bc-22__nav" aria-label="Documentation breadcrumb">
<ol class="bc-22__list">
<li><a href="#">docs</a></li>
<li><a href="#">api</a></li>
<li><a href="#">authentication</a></li>
<li><a aria-current="page" href="#">oauth2</a></li>
</ol>
<button type="button" class="bc-22__copy" aria-label="Copy path to clipboard" data-cf-track="copy_path_click">
<svg class="bc-22__icon bc-22__icon--copy" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
<svg class="bc-22__icon bc-22__icon--check" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="m5 12 5 5L20 7"/></svg>
</button>
<span class="bc-22__sr" role="status" aria-live="polite" aria-atomic="true"></span>
</nav>
</section>
```
## CSS
```css
.bc-22 {
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 2rem 1.25rem;
background: radial-gradient(1200px 600px at 50% -10%, oklch(0.28 0.05 265 / 0.55), transparent 60%), oklch(0.16 0.02 260);
font-family: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
color: oklch(0.82 0.02 260);
--bc18-accent: oklch(0.78 0.17 300);
--bc18-muted: oklch(0.58 0.02 260);
--bc18-sep: oklch(0.42 0.02 260);
--bc18-surface: oklch(0.21 0.02 260);
--bc18-border: oklch(0.32 0.02 260 / 0.6);
}
.bc-22 *,
.bc-22 *::before,
.bc-22 *::after {
box-sizing: border-box;
}
.bc-22__nav {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.5rem 0.5rem 1rem;
background: var(--bc18-surface);
border: 1px solid var(--bc18-border);
border-radius: 12px;
box-shadow: 0 1px 0 oklch(1 0 0 / 0.04) inset, 0 10px 30px -12px oklch(0 0 0 / 0.6);
font-size: 0.9375rem;
line-height: 1.2;
max-width: 100%;
overflow-x: auto;
scrollbar-width: thin;
scrollbar-color: var(--bc18-border) transparent;
}
.bc-22__list {
list-style: none;
margin: 0;
padding: 0;
display: inline-flex;
align-items: center;
flex-wrap: nowrap;
gap: 0.25rem;
}
.bc-22__list li {
display: inline-flex;
align-items: center;
gap: 0.25rem;
white-space: nowrap;
}
.bc-22__list li + li::before {
content: "/";
color: var(--bc18-sep);
padding: 0 0.25rem;
user-select: none;
}
.bc-22__list a {
color: var(--bc18-muted);
text-decoration: none;
padding: 0.375rem 0.5rem;
border-radius: 6px;
transition: color 160ms ease, background-color 160ms ease;
}
.bc-22__list a:hover {
color: oklch(0.92 0.02 260);
background: color-mix(in oklch, var(--bc18-accent) 8%, transparent);
}
.bc-22__list a[aria-current="page"] {
color: var(--bc18-accent);
background: color-mix(in oklch, var(--bc18-accent) 12%, transparent);
font-weight: 600;
cursor: default;
}
.bc-22__list a:focus-visible,
.bc-22__copy:focus-visible {
outline: 2px solid var(--bc18-accent);
outline-offset: 2px;
border-radius: 6px;
}
.bc-22__copy {
appearance: none;
border: 1px solid var(--bc18-border);
background: color-mix(in oklch, var(--bc18-surface) 70%, oklch(0.28 0.02 260));
color: oklch(0.82 0.02 260);
min-width: 44px;
min-height: 44px;
width: 44px;
height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
position: relative;
transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease, transform 160ms ease;
flex-shrink: 0;
}
.bc-22__copy:hover {
color: oklch(0.95 0.02 260);
border-color: color-mix(in oklch, var(--bc18-accent) 40%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 10%, var(--bc18-surface));
}
.bc-22__copy:active {
transform: scale(0.96);
}
.bc-22__icon {
width: 18px;
height: 18px;
position: absolute;
inset: 0;
margin: auto;
transition: opacity 180ms ease, transform 180ms ease;
}
.bc-22__icon--check {
color: var(--bc18-accent);
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--copy {
opacity: 0;
transform: scale(0.6);
}
.bc-22__copy.is-copied .bc-22__icon--check {
opacity: 1;
transform: scale(1);
}
.bc-22__copy.is-copied {
border-color: color-mix(in oklch, var(--bc18-accent) 60%, var(--bc18-border));
background: color-mix(in oklch, var(--bc18-accent) 15%, var(--bc18-surface));
}
.bc-22__sr {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (prefers-reduced-motion: reduce) {
.bc-22__list a,
.bc-22__copy,
.bc-22__icon {
transition: none;
}
.bc-22__copy:active {
transform: none;
}
}
@media (max-width: 480px) {
.bc-22__nav {
font-size: 0.8125rem;
padding-left: 0.75rem;
}
}
```
## JavaScript
```js
(() => {
const btn = document.querySelector('.bc-22__copy');
if (!btn) return;
const live = document.querySelector('.bc-22 .bc-22__sr');
const path = 'docs/api/authentication/oauth2';
btn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(path);
btn.classList.add('is-copied');
if (live) live.textContent = 'Path copied to clipboard';
setTimeout(() => {
btn.classList.remove('is-copied');
if (live) live.textContent = '';
}, 1200);
} catch (err) {
// Clipboard API can fail on http:// or if permission denied — fail silently in demo.
}
});
})();
```How this works
The visual grammar borrows from a terminal prompt: a near-black surface with a subtle blue tint, a monospace stack (ui-monospace, JetBrains Mono, SF Mono), slash separators in a muted tone, and syntax coloring per segment. Parent crumbs render in a low-contrast gray while the current segment lights up in an accent violet driven by oklch(), so the active location reads at a glance the same way a shell prompt telegraphs the current directory. A clipboard icon button sits flush to the end of the path; on click the Clipboard API writes the joined string, an .is-copied class swaps the copy glyph for a checkmark for 1.2s, and a visually-hidden aria-live=polite region announces the state change for screen readers before quietly clearing itself.
The markup is a real nav landmark wrapping an ordered list, with aria-current=page on the terminal crumb and a semantic button (not a div) carrying an aria-label for the copy action. Focus rings are driven by :focus-visible with a 2px accent outline, hit targets clear 44px on the copy control, and every transition is gated by prefers-reduced-motion so the icon swap simply cuts on reduced-motion setups. Scoping under .bc-22 keeps the demo framework-agnostic and safe to drop into any page.
Make it yours
- Accent color: swap --bc18-accent oklch() lightness/chroma or shift hue toward cyan (200) for a Docker-style look.
- Monospace stack: reorder the font-family to prefer Geist Mono, Fira Code, or IBM Plex Mono if your docs already load one.
- Checkmark duration: change the 1200ms setTimeout in the JS to match your site's toast timing conventions.
- Separator: replace the '/' content in .bc-22__list li + li::before with '›', '>', or a bullet for a softer non-path feel.
Gotchas — read before shipping
- Clipboard API requires a secure context (HTTPS or localhost). On plain http:// navigator.clipboard is undefined and writeText throws; the demo catches silently but production should show a fallback tooltip.
- navigator.clipboard.writeText returns a Promise, so the handler is async and the class swap must live inside the await/try block, otherwise the checkmark can flash even when the write rejected.
- aria-live regions only announce diffs, so clearing textContent before setting the next message (or reusing the same string) is required or repeat copies stay silent for screen reader users.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.2+ | 113+ | 111+ |
Floor set by oklch(), color-mix() as this demo is written. The core technique itself goes back further — Chrome 66+.
Clipboard API needs HTTPS or localhost. Ships with try/catch fallback that logs failure without breaking the button.