Skip to main content
Settings
Search
Appearance
Theme Mode
About
Jekyll v3.10.0
Environment Production
Last Build
2026-04-06 19:49 UTC
Current Environment Production
Build Time Apr 06, 19:49
Jekyll v3.10.0
Build env (JEKYLL_ENV) production
Page Location
Page Info
Layout default
Collection docs
Path _docs/features/code-copy.md
URL /docs/features/code-copy/
Date 2026-04-06
Theme Skin
SVG Backgrounds
Layer Opacity
0.6
0.04
0.08

Code Copy Button

Automatic copy buttons on all code blocks for easy clipboard copying.

Overview

  • Automatic Injection: Buttons added to all code blocks
  • Clipboard API: Modern async clipboard access
  • Visual Feedback: “Copied!” confirmation
  • Accessible: ARIA labels and keyboard support

Implementation

JavaScript

document.addEventListener('DOMContentLoaded', function() {
  document.querySelectorAll('pre.highlight, pre code').forEach(function(pre) {
    // Skip if already has button
    if (pre.querySelector('.copy')) return;
    
    var preElement = pre.tagName === 'PRE' ? pre : pre.closest('pre');
    if (!preElement) return;
    
    var button = document.createElement('button');
    button.className = 'copy';
    button.type = 'button';
    button.setAttribute('aria-label', 'Copy code to clipboard');
    button.innerHTML = '<i class="bi bi-clipboard me-1"></i>Copy';
    
    button.addEventListener('click', function(e) {
      e.preventDefault();
      var code = preElement.querySelector('code');
      if (!code) return;
      
      navigator.clipboard.writeText(code.textContent).then(function() {
        button.innerHTML = '<i class="bi bi-check me-1"></i>Copied!';
        setTimeout(function() {
          button.innerHTML = '<i class="bi bi-clipboard me-1"></i>Copy';
        }, 2000);
      });
    });
    
    preElement.appendChild(button);
  });
});

Styling

Button Positioning

pre.highlight {
  position: relative;
}

pre .copy {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.75rem;
  background: var(--bs-secondary);
  color: white;
  border: none;
  border-radius: var(--bs-border-radius);
  opacity: 0;
  transition: opacity 0.2s;
}

pre:hover .copy {
  opacity: 1;
}

pre .copy:hover {
  background: var(--bs-primary);
}

Success State

pre .copy.copied {
  background: var(--bs-success);
}

Customization

Button Text

var copyText = 'Copy';
var copiedText = 'Copied!';

Icons

// Bootstrap Icons
button.innerHTML = '<i class="bi bi-clipboard"></i>';

// Text only
button.textContent = 'Copy';

// SVG icon
button.innerHTML = '<svg>...</svg>';

Always Visible

pre .copy {
  opacity: 1;
}

Different Position

/* Bottom right */
pre .copy {
  top: auto;
  bottom: 0.5rem;
}

/* Top left */
pre .copy {
  right: auto;
  left: 0.5rem;
}

Clipboard API

Modern Approach

navigator.clipboard.writeText(text)
  .then(() => console.log('Copied!'))
  .catch(err => console.error('Failed to copy:', err));

Fallback for Older Browsers

function copyToClipboard(text) {
  if (navigator.clipboard) {
    return navigator.clipboard.writeText(text);
  }
  
  // Fallback
  var textarea = document.createElement('textarea');
  textarea.value = text;
  textarea.style.position = 'fixed';
  document.body.appendChild(textarea);
  textarea.select();
  document.execCommand('copy');
  document.body.removeChild(textarea);
  return Promise.resolve();
}

Accessibility

ARIA Labels

<button aria-label="Copy code to clipboard"
        title="Copy code to clipboard">
  Copy
</button>

Focus Styles

pre .copy:focus {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
}

pre .copy:focus-visible {
  opacity: 1;
}

Screen Reader Feedback

// Announce copy success
button.setAttribute('aria-label', 'Copied to clipboard');
setTimeout(() => {
  button.setAttribute('aria-label', 'Copy code to clipboard');
}, 2000);

Language-Specific

Skip Certain Languages

// Don't add to terminal output
if (pre.classList.contains('language-output')) return;
if (pre.classList.contains('language-console')) return;

Custom Label by Language

var lang = pre.className.match(/language-(\w+)/);
if (lang) {
  button.setAttribute('aria-label', `Copy ${lang[1]} code`);
}

Troubleshooting

Button Not Appearing

  1. Check code block has pre.highlight or pre code
  2. Verify JavaScript is loaded
  3. Check CSS isn’t hiding button
  4. Inspect for duplicate buttons

Copy Not Working

  1. Check browser clipboard permissions
  2. Verify HTTPS (required for Clipboard API)
  3. Test fallback method
  4. Check for JavaScript errors

Styling Issues

  1. Verify position: relative on pre
  2. Check z-index conflicts
  3. Test hover states
  4. Verify button is inside pre