Business & Operations

Free Scheduler Button Widget

A "Book a call" button that sends visitors straight to your scheduling link.

A polished call-to-action button that links to your Calendly, Cal.com, or any scheduling page. Use it inline inside your content or as a floating button pinned to the corner of the screen. Install it with a single script tag and one required attribute.

Live demo

Embed this widget

Paste either snippet into your page — a Custom HTML block on WordPress, Shopify, or Squarespace works too. Both snippets update live as you customize, so what you copy is exactly what you configured.

Hosted (recommended)html
<script src="https://hayneslab.dev/widgets/scheduler-button.js" data-hl-link="https://cal.com/" data-hl-label="Book a free consultation" data-hl-subtext="Usually replies within 1 business day" data-hl-position="floating" async></script>
<!-- Free Scheduler Button widget by haynes lab — https://hayneslab.dev/tools/widgets/scheduler-button -->
Inline (self-contained)html
<!-- Free Scheduler Button widget by haynes lab — https://hayneslab.dev/tools/widgets/scheduler-button -->
<script data-hl-link="https://cal.com/" data-hl-label="Book a free consultation" data-hl-subtext="Usually replies within 1 business day" data-hl-position="floating">
/*!
 * haynes lab — Scheduler Button widget (free)
 * Docs & embed code: https://hayneslab.dev/tools/widgets/scheduler-button
 */
(function () {
  'use strict';

  var PREFIX = 'hlw-scheduler-button';
  var STYLE_ID = 'hlw-scheduler-button-styles';

  function findScript() {
    return document.currentScript ||
      document.querySelector('script[src*="widgets/scheduler-button.js"]');
  }

  function injectStyles() {
    if (document.getElementById(STYLE_ID)) return;
    var css =
      '.' + PREFIX + ', .' + PREFIX + ' * { box-sizing: border-box; }' +
      '.' + PREFIX + ' { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;' +
      ' font-size: 16px; line-height: 1.5; color: #1f2937; }' +
      '.' + PREFIX + '--inline { display: flex; flex-direction: column; align-items: center; gap: 8px;' +
      ' padding: 16px; text-align: center; }' +
      '.' + PREFIX + '--floating { position: fixed; right: 20px; bottom: 20px; z-index: 99999;' +
      ' display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }' +
      '.' + PREFIX + '--floating.' + PREFIX + '--in-stage { position: absolute; z-index: 10; }' +
      '.' + PREFIX + '__button { display: inline-flex; align-items: center; gap: 10px; padding: 14px 28px;' +
      ' border: 0; border-radius: 999px; background: #f97316; color: #ffffff; font-size: 16px; font-weight: 600;' +
      ' font-family: inherit; line-height: 1.2; text-decoration: none; cursor: pointer;' +
      ' box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15); transition: transform 0.15s ease, box-shadow 0.15s ease; }' +
      '.' + PREFIX + '__button:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); }' +
      '.' + PREFIX + '__button:focus-visible { outline: 2px solid #1f2937; outline-offset: 3px; }' +
      '.' + PREFIX + '__button svg { display: block; flex: 0 0 auto; }' +
      '.' + PREFIX + '__subtext { margin: 0; font-size: 13px; color: #6b7280; }' +
      '.' + PREFIX + '--floating .' + PREFIX + '__subtext { padding: 4px 10px; background: #ffffff;' +
      ' border: 1px solid #e5e7eb; border-radius: 999px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }' +
      '.' + PREFIX + '__credit { font-size: 11px; display: inline-flex; align-items: center; gap: 4px;' +
      ' color: #9ca3af; text-decoration: none; }' +
      '.' + PREFIX + '__credit svg { display: block; }' +
      '.' + PREFIX + '__credit:hover { color: #6b7280; text-decoration: underline; }' +
      '@media (max-width: 560px) {' +
      ' .' + PREFIX + '--floating { right: 14px; bottom: 14px; }' +
      ' .' + PREFIX + '__button { padding: 12px 22px; font-size: 15px; } }';
    var style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent = css;
    document.head.appendChild(style);
  }

  function el(tag, className, text) {
    var node = document.createElement(tag);
    if (className) node.className = className;
    if (text != null) node.textContent = text;
    return node;
  }

  function calendarSvg() {
    var svgNS = 'http://www.w3.org/2000/svg';
    var svg = document.createElementNS(svgNS, 'svg');
    svg.setAttribute('viewBox', '0 0 24 24');
    svg.setAttribute('width', '18');
    svg.setAttribute('height', '18');
    svg.setAttribute('fill', 'none');
    svg.setAttribute('stroke', 'currentColor');
    svg.setAttribute('stroke-width', '2');
    svg.setAttribute('stroke-linecap', 'round');
    svg.setAttribute('stroke-linejoin', 'round');
    svg.setAttribute('aria-hidden', 'true');
    svg.setAttribute('focusable', 'false');
    var shapes = [
      ['rect', { x: 3, y: 4, width: 18, height: 18, rx: 2 }],
      ['line', { x1: 16, y1: 2, x2: 16, y2: 6 }],
      ['line', { x1: 8, y1: 2, x2: 8, y2: 6 }],
      ['line', { x1: 3, y1: 10, x2: 21, y2: 10 }],
    ];
    shapes.forEach(function (s) {
      var node = document.createElementNS(svgNS, s[0]);
      for (var key in s[1]) node.setAttribute(key, s[1][key]);
      svg.appendChild(node);
    });
    return svg;
  }

  function logoSvg() {
    var svgNS = 'http://www.w3.org/2000/svg';
    var svg = document.createElementNS(svgNS, 'svg');
    svg.setAttribute('viewBox', '0 0 32 32');
    svg.setAttribute('width', '13');
    svg.setAttribute('height', '13');
    svg.setAttribute('aria-hidden', 'true');
    svg.setAttribute('focusable', 'false');
    function circle(cx, cy, r, attrs) {
      var c = document.createElementNS(svgNS, 'circle');
      c.setAttribute('cx', cx);
      c.setAttribute('cy', cy);
      c.setAttribute('r', r);
      for (var key in attrs) c.setAttribute(key, attrs[key]);
      svg.appendChild(c);
    }
    circle(16, 16, 16, { fill: '#0f0a0a' });
    circle(16, 16, 12, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1, opacity: 0.3 });
    circle(16, 16, 9, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1, opacity: 0.5 });
    circle(16, 16, 6, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1.2, opacity: 0.9 });
    circle(16, 16, 3, { fill: '#06b6d4' });
    circle(24.5, 7.5, 2, { fill: '#f97316' });
    circle(7, 16, 1.8, { fill: '#f97316' });
    circle(20, 20, 1.5, { fill: '#f97316' });
    return svg;
  }

  function build(script) {
    var link = script.getAttribute('data-hl-link');
    if (!link) {
      console.warn('[haynes lab scheduler-button] Missing required data-hl-link attribute (your Calendly or Cal.com URL). Nothing rendered.');
      return;
    }

    var label = script.getAttribute('data-hl-label') || 'Book a call';
    var subtext = script.getAttribute('data-hl-subtext');
    var bg = script.getAttribute('data-hl-bg') || '#f97316';
    var floating = script.getAttribute('data-hl-position') === 'floating';
    var stage = script.closest('.widget-demo__stage');

    injectStyles();

    var root = el('div', PREFIX + ' ' + PREFIX + (floating ? '--floating' : '--inline'));

    var button = el('a', PREFIX + '__button');
    button.href = link;
    button.target = '_blank';
    button.rel = 'noopener';
    button.style.background = bg;
    button.appendChild(calendarSvg());
    button.appendChild(el('span', null, label));
    root.appendChild(button);

    if (subtext) root.appendChild(el('p', PREFIX + '__subtext', subtext));

    var credit = el('a', PREFIX + '__credit');
    credit.appendChild(logoSvg());
    credit.appendChild(document.createTextNode('Powered by haynes lab'));
    credit.href = 'https://hayneslab.dev/tools/widgets/scheduler-button';
    credit.target = '_blank';
    credit.rel = 'noopener';
    root.appendChild(credit);

    if (floating) {
      if (stage) {
        root.classList.add(PREFIX + '--in-stage');
        stage.appendChild(root);
      } else {
        document.body.appendChild(root);
      }
    } else if (script.parentNode && script.parentNode.nodeName !== 'HEAD') {
      script.insertAdjacentElement('afterend', root);
    } else {
      document.body.appendChild(root);
    }
  }

  function init() {
    var script = findScript();
    if (!script) {
      console.warn('[haynes lab scheduler-button] Could not locate its own script tag. Nothing rendered.');
      return;
    }
    build(script);
  }

  if (document.body) {
    init();
  } else {
    document.addEventListener('DOMContentLoaded', init);
  }
})();

</script>

Configuration

Every option is an attribute on the script tag — the same attributes the customizer above exposes. All attributes are optional unless marked required — defaults apply when omitted.

AttributeDefaultDescription
data-hl-link(required)Your Calendly, Cal.com, or other scheduling URL the button opens in a new tab.
data-hl-label"Book a call"The text shown on the button.
data-hl-subtext(none)Optional smaller line of text shown next to the button, such as availability or response time.
data-hl-position"inline"Set to "floating" to pin the button to the bottom-right corner of the screen instead of placing it inline.
data-hl-bg"#f97316"Background color of the button.

Frequently asked questions

How do I install the Scheduler Button?

Paste the script tag where you want the button to appear and set data-hl-link to your Calendly or Cal.com URL. The button renders inline right where the tag is placed; add data-hl-position="floating" to pin it to the bottom-right corner of the screen instead.

Can I change the text and color?

Yes — data-hl-label sets the button text, data-hl-subtext adds an optional secondary line (like your availability), and data-hl-bg sets the button background color to match your brand.

Does it work on WordPress, Shopify, or Squarespace?

Yes — it is a single vanilla JavaScript file with no dependencies. Paste the snippet into any platform that lets you add custom scripts or edit your theme, including WordPress, Shopify, Squarespace, Wix, and plain HTML sites.

More free widgets

Need a custom widget?

We build custom widgets, integrations, and whole products. Tell us what your site needs and we'll scope it.

Get in Touch