Tutorials
Last updated on:
Feb 12, 2025

How to add URL copy button functionality in Webflow

BRIX Templates Logo
Author
BRIX Templates
How to add URL copy button functionality in Webflow
Table of contents

Adding URL copy functionality to your Webflow site enhances content sharing and improves user experience. Whether you're running a blog, portfolio, or e-commerce site, making it easy for visitors to share your pages can significantly boost your site's reach and engagement.

This guide will show you how to implement a simple, attribute-based solution for adding a button for copying page URLs on your Webflow site.

Add copy URL script Webflow

Why you should add URL copy functionality to your Webflow site

Here are some practical applications where URL copy functionality can enhance your Webflow site:

  • Blog post sharing: Give readers a quick way to copy article URLs for sharing on social media or messaging apps, increasing your content's reach without relying on standard share buttons.
  • Product recommendations: Enable customers to easily copy product page URLs to share with friends or save for later, enhancing word-of-mouth marketing and simplifying the buying decision process.
  • Event registration: Help attendees share event pages with their network by providing a simple URL copy button, increasing event visibility and attendance.
  • Resource linking: Make it simple for users to copy URLs of documentation pages, tutorials, or resources, facilitating knowledge sharing within teams.

How to add the URL copy script to your Webflow project

Let's implement the URL copy functionality step by step:

  1. Navigate to your Webflow project settings
  2. Access the Custom Code section
  3. Locate the "Before </body> tag" field
  4. Insert the following code:
Copy URL button Webflow
<script>
/*!
 * BRIX Templates Copy to Clipboard Attribute for Webflow
 * ----------------------------------------------------------------------------
 * Automatically enables copy-to-clipboard functionality on elements marked with
 * the appropriate attributes. This script supports two main copying modes:
 * 
 * 1. Custom Text Copying:
 *    - Add [brix-copy-clipboard="true"] to enable copying
 *    - Add [brix-copy-clipboard-text="Your text"] to specify what to copy
 * 
 * 2. URL Copying:
 *    - Add [brix-copy-clipboard="true"] to enable copying
 *    - Add [brix-copy-clipboard-url="true"] to copy the current page URL
 * 
 * Optional Attributes for Both Modes:
 *    - [brix-copy-clipboard-successtext="Copied!"] 
 *      Shows a temporary success message after copying
 * 
 *    - [brix-copy-clipboard-successclass="is-copied"]
 *      Adds a temporary class for styling feedback
 * 
 *    - [brix-copy-clipboard-revertms="2000"]
 *      Controls how long success state lasts (default: 1500ms)
 * 
 * The script includes:
 *    - Automatic success feedback
 *    - Screen reader support via ARIA
 *    - Keyboard accessibility
 *    - Detailed console logging for debugging
 * 
 * Version: 1.0.1
 * Author: BRIX Templates
 * 
 */

(function() {
  'use strict';

  //--------------------------------------------------------------------------
  // 1) Configuration & Constants
  //--------------------------------------------------------------------------
  const SCRIPT_VERSION = '1.0.1';
  const DEFAULT_REVERT_MS = 1500;
  const ARIA_ANNOUNCE_DEFAULT = 'Copied to clipboard';

  let ariaLiveContainer = null;

  //--------------------------------------------------------------------------
  // 2) Initialize on DOM Ready
  //--------------------------------------------------------------------------
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initBrixClipboard);
  } else {
    initBrixClipboard();
  }

  //--------------------------------------------------------------------------
  // 3) Main Initialization
  //--------------------------------------------------------------------------
  function initBrixClipboard() {
    // 3.1) Find all elements with brix-copy-clipboard="true"
    const triggers = document.querySelectorAll('[brix-copy-clipboard="true"]');
    const total = triggers.length;
    if (total === 0) return;

    // 3.2) Create a hidden ARIA-live region for screenreader announcements
    ariaLiveContainer = createAriaLiveRegion();

    // 3.3) Console logging: Intro summary
    console.log('------------------------');
    console.log(
      '%c[BRIX Templates Copy to Clipboard for Webflow]%c v' + SCRIPT_VERSION +
      ' Activated. Found %c' + total + '%c element' + (total !== 1 ? 's' : '') + ' to manage:',
      'font-weight:bold;',
      'font-weight:normal;',
      'font-weight:bold;',
      'font-weight:normal;'
    );
    console.log('------------------------');

    // 3.4) For each trigger, parse attributes & log
    triggers.forEach((elem, index) => {
      const info = parseAttributes(elem, index);

      // (A) Per-element line #1
      console.log(
        '- Element #%c' + (index + 1) + '%c: %c' + info.identifier,
        'font-weight:bold;',
        'font-weight:normal;',
        'font-weight:bold;'
      );

      // (B) Per-element line #2 - attributes summary
      console.log(
        '    copyingURL=%c' + info.isUrl + '%c, text="%c' + info.textAttr + '%c", successText="%c' +
        info.successText + '%c", successClass="%c' + info.successClass + '%c", revertMs=%c' + info.revertMs,
        'font-weight:bold;',
        'font-weight:normal;',
        'font-weight:bold;',
        'font-weight:normal;',
        'font-weight:bold;',
        'font-weight:normal;',
        'font-weight:bold;',
        'font-weight:normal;',
        'font-weight:bold;',
        'font-weight:normal;'
      );

      // (C) Warnings & conflicts (same indentation)
      if (info.urlAndTextConflict) {
        console.warn(
          '    "url" specified alongside "text=' + info.textAttr +
          '". "url" takes precedence, ignoring text.'
        );
      }
      if (info.invalidRevertMs) {
        console.warn(
          '    Invalid revertMs="' + info.revertMsStr + '". Using default ' + DEFAULT_REVERT_MS + '.'
        );
      }

      // (D) Attach click listener
      elem.addEventListener('click', (evt) => {
        evt.preventDefault();
        handleCopyAction(elem, index);
      });
    });

    // 3.5) Final line after listing triggers
    console.log('------------------------');
    console.log(
      '%c[BRIX Templates Copy to Clipboard for Webflow]%c All copy triggers have been initialized successfully.',
      'font-weight:bold;',
      'font-weight:normal;'
    );
    console.log('------------------------');
  }

  //--------------------------------------------------------------------------
  // 4) Parse Attributes (for logging)
  //--------------------------------------------------------------------------
  // This function only logs the data; the actual fallback or overrides
  // still happen in handleCopyAction for the real copy process.
  function parseAttributes(elem, index) {
    const identifier = getElementIdentifier(elem, index);

    // Gather
    const rawUrl = (elem.getAttribute('brix-copy-clipboard-url') || '').toLowerCase();
    const isUrl = (rawUrl === 'true');
    const textAttr = elem.getAttribute('brix-copy-clipboard-text') || '';
    const successText = elem.getAttribute('brix-copy-clipboard-successtext') || '';
    const successClass = elem.getAttribute('brix-copy-clipboard-successclass') || '';
    const revertMsStr = elem.getAttribute('brix-copy-clipboard-revertms');
    let revertMsNum = parseInt(revertMsStr, 10);
    let invalidRevertMs = false;

    if (isNaN(revertMsNum) || revertMsNum < 0) {
      invalidRevertMs = !!revertMsStr; // only warn if the user tried to set a revertMs
      revertMsNum = (invalidRevertMs) ? 0 : DEFAULT_REVERT_MS;
      // We'll do the real fallback in handleCopyAction, but log here for clarity.
    }

    // Conflicts
    const urlAndTextConflict = (isUrl && textAttr.trim().length > 0);

    return {
      identifier,
      isUrl,
      textAttr,
      successText,
      successClass,
      revertMs: revertMsNum,
      revertMsStr,
      invalidRevertMs,
      urlAndTextConflict
    };
  }

  //--------------------------------------------------------------------------
  // 5) Build a readable identifier for the element
  //--------------------------------------------------------------------------
  function getElementIdentifier(elem, index) {
    if (elem.id) {
      return 'ID: "' + elem.id + '"';
    }
    else if (elem.classList && elem.classList.length > 0) {
      return 'Classes: "' + Array.from(elem.classList).join(' ') + '"';
    }
    else {
      return 'element-' + (index + 1);
    }
  }

  //--------------------------------------------------------------------------
  // 6) Handle the actual copy action (on click)
  //--------------------------------------------------------------------------
  function handleCopyAction(element, index) {
    const originalText = element.textContent;

    // Collect attributes again for actual logic/fallback
    const isUrl = (element.getAttribute('brix-copy-clipboard-url') || '').toLowerCase() === 'true';
    const textAttr = element.getAttribute('brix-copy-clipboard-text');
    const successText = element.getAttribute('brix-copy-clipboard-successtext') || '';
    const successClass = element.getAttribute('brix-copy-clipboard-successclass') || '';
    let revertMs = parseInt(element.getAttribute('brix-copy-clipboard-revertms'), 10);

    if (isNaN(revertMs) || revertMs < 0) {
      revertMs = DEFAULT_REVERT_MS;
      // We no longer console.warn here, because we already did it in initBrixClipboard logs
    }

    // Decide what text to copy
    let textToCopy = '';
    if (isUrl) {
      textToCopy = window.location.href;
    } else if (textAttr) {
      textToCopy = textAttr;
    } else {
      textToCopy = originalText.trim();
    }

    doCopyText(textToCopy);

    // Provide success feedback
    const finalSuccessText = successText || ARIA_ANNOUNCE_DEFAULT;

    if (successText) {
      element.textContent = successText;
    }
    if (successClass) {
      element.classList.add(successClass);
    }

    announceAriaLive(finalSuccessText);

    // Revert after revertMs
    setTimeout(() => {
      element.textContent = originalText;
      if (successClass) {
        element.classList.remove(successClass);
      }
    }, revertMs);
  }

  //--------------------------------------------------------------------------
  // 7) Copy Logic (Modern + Fallback)
  //--------------------------------------------------------------------------
  function doCopyText(str) {
    // Attempt modern async clipboard API first
    if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
      navigator.clipboard.writeText(str).catch((err) => {
        // Already in fallback, no bracket prefix here
        console.warn('    Clipboard API error:', err);
        fallbackCopyText(str);
      });
    }
    // Attempt document.execCommand('copy') if available
    else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
      fallbackCopyText(str);
    }
    else {
      console.warn('    No browser copy support found. Copy may fail.');
    }
  }

  // Fallback for older browsers
  function fallbackCopyText(str) {
    const temp = document.createElement('textarea');
    temp.value = str;
    temp.setAttribute('readonly', '');
    temp.style.position = 'absolute';
    temp.style.left = '-9999px';
    document.body.appendChild(temp);

    temp.select();
    try {
      document.execCommand('copy');
    } catch (err) {
      console.warn('    execCommand("copy") failed:', err);
    }
    document.body.removeChild(temp);
  }

  //--------------------------------------------------------------------------
  // 8) Create ARIA Live Region for Screenreaders
  //--------------------------------------------------------------------------
  function createAriaLiveRegion() {
    let region = document.getElementById('brix-copy-aria-live');
    if (region) return region;

    region = document.createElement('div');
    region.id = 'brix-copy-aria-live';
    region.setAttribute('aria-live', 'polite');
    region.setAttribute('aria-atomic', 'true');
    region.style.position = 'absolute';
    region.style.left = '-9999px';
    region.style.width = '1px';
    region.style.height = '1px';
    region.style.overflow = 'hidden';
    document.body.appendChild(region);

    return region;
  }

  //--------------------------------------------------------------------------
  // 9) Announce to Screenreaders
  //--------------------------------------------------------------------------
  function announceAriaLive(message) {
    if (!ariaLiveContainer) return;
    ariaLiveContainer.textContent = '';
    setTimeout(() => {
      ariaLiveContainer.textContent = message;
    }, 50);
  }

})();
</script>

Page-specific implementation

If you only want URL copy buttons on certain pages (like blog posts or product pages), you can add the script to individual page settings instead:

  1. Navigate to the specific page in your Webflow Designer
  2. Click the settings gear icon (⚙️) in the top right
  3. Select "Page Settings"
  4. Scroll to the "Custom Code" section
  5. Add the script to the "Before </body> tag" field
Copy current URL tutorial

This targeted approach helps maintain site performance by loading the copy URL functionality only where needed.

How to configure URL copy elements in your Webflow site

After adding the script, here's how to set up a URL copy button:

  1. Select your target button or link in the Webflow Designer
  2. Open the element's Settings panel (gear icon)
  3. Locate the Custom Attributes section
  4. Add the following attributes:
Webflow URL copy integration

Required attributes

brix-copy-clipboard

  • Value: true
  • What it does: Activates the copy functionality on your button or link element.

brix-copy-clipboard-url

  • Value: true
  • What it does: Tells the system to copy the current page's URL instead of custom text.

Optional attributes (Add these only if you need them)

brix-copy-clipboard-successtext

  • Value: Link copied! (or your custom message)
  • What it does: Shows a temporary confirmation message after copying the URL.

brix-copy-clipboard-successclass

  • Value: url-copied (or your custom class name)
  • What it does: Adds temporary styling to show the copy was successful.

brix-copy-clipboard-revertms

  • Value: 2000 (milliseconds)
  • What it does: Sets how long the success state remains visible.

This setup creates a button that copies the current page's URL when clicked, shows a confirmation, and can provide visual feedback through temporary styling.

How to test your URL copy implementation

Before publishing, verify your implementation:

  1. Test on your staging environment (webflow.io domain)
  2. Verify the URL copying works on different page types
  3. If you've added optional features, test them as well:
    • Success message appears (if configured)
    • Success class applies (if configured)
    • Element reverts correctly after your specified time
  4. Test across different pages to ensure the correct URL is always copied
  5. Publish to your production domain after confirming everything works as expected

Final thoughts

Adding URL copy functionality to your Webflow site using custom attributes provides a seamless way to enhance content sharing and improve user experience. Whether you're running a blog, portfolio, or ecommerce site, this implementation makes it effortless for visitors to share your pages while maintaining professional design standards.

Need help implementing more advanced sharing features or exploring other custom Webflow solutions? Our top-notch Webflow agency specializes in creating tailored functionality that enhances your site's user experience while maintaining performance and reliability. Feel free to reach out to discuss how we can help optimize your Webflow project.

BRIX Templates Logo
About BRIX Templates

At BRIX Templates we craft beautiful, modern and easy to use Webflow templates & UI Kits.

Explore our Webflow templates
Join the conversation
Join our monthly Webflow email newsletter!

Receive one monthly email newsletter with the best articles, resources, tutorials, and free cloneables from BRIX Templates!

Webflow Newsletter
Thanks for joining our Webflow email newsletter
Oops! Something went wrong while submitting the form.
BRIX Templates - Email Newsletter with Webflow ResourcesBRIX Templates - Email NewsletterBRIX Templates - Webflow Email Newsletter
How to add animated number counters to your Webflow site

How to add animated number counters to your Webflow site

Learn how to add animated number counters to your Webflow site. This step-by-step guide explains how to do it in 5 minutes or less.

Feb 19, 2025
How to add copy-to-clipboard functionality to a button in Webflow

How to add copy-to-clipboard functionality to a button in Webflow

Learn how to add copy-to-clipboard button to your Webflow site in 5 minutes or less.

Feb 12, 2025
How to geo-block visitors on your Webflow site using Cloudflare

How to geo-block visitors on your Webflow site using Cloudflare

Complete tutorial explaining how to prevent users from specific countries from accessing your Webflow website.

Feb 12, 2025