Documentation

buy-me-a-coffee-cta

A scroll-driven Buy Me a Coffee floating button for any website. Vanilla JavaScript, zero dependencies.

Try the playground View on npm

Install

pnpm add buy-me-a-coffee-cta

Quick start

import { createCoffeeCta } from "buy-me-a-coffee-cta";
import "buy-me-a-coffee-cta/style.css";

createCoffeeCta({
  username: "yourname",
  label: "Buy me a coffee",
  emoji: "☕",
});

Use the playground to tune options visually and copy a ready-to-paste snippet for Vanilla JS, React, Vue, Solid, Angular, or Svelte.

CDN (no bundler)

<link rel="stylesheet" href="https://unpkg.com/buy-me-a-coffee-cta/dist/style.css" />
<script type="module">
  import { createCoffeeCta } from "https://unpkg.com/buy-me-a-coffee-cta/dist/index.js";
  createCoffeeCta({ username: "yourname" });
</script>

Configuration

Option Type Default Description
username string BMC username (used if url is omitted)
url string Full BMC profile URL
label string "Buy me a coffee" Tooltip text
emoji string "" Optional emoji prefix in tooltip
size number 40 Cup size in px (desktop)
position preset or offsets "bottom-right" Corner preset or custom offsets (fixed mode only)
anchor Element | string | null null In-flow placement inside an element; ignores position
tooltipPosition "auto" | … "auto" Tooltip side relative to the cup — same on desktop and mobile
theme.* string BMC defaults yellow, ink, chipBg, chipFg, …
darkTheme.* string dark defaults Overrides when dark mode is active
darkMode "auto" | "class" | … "auto" auto = CSS; media / class = JS — see Dark theme
scroll.* object see README target, reverse, fillDelay, …

See the full option list on GitHub for every property and default.

API

const cta = createCoffeeCta({ username: "yourname" });

cta.updateConfig({ label: "Support my work" });
cta.destroy();
cta.element; // HTMLAnchorElement

Only one CTA per page is supported. Creating a second instance destroys the previous one.

The CTA stays hidden until scroll animation begins. Short pages that fit in the viewport stay visible when the cup would already be full.

Tooltip

Use tooltipPosition to pick a side: left, right, top, bottom, or auto (default).

  • Fixed modeauto places the tooltip on the left (or right when the CTA is left-aligned).
  • Flow mode (anchor set) — auto places the tooltip on the right.

The tooltip uses the same side on desktop and mobile. Desktop shows it on hover; mobile shows it on tap, then auto-hides after scroll.touchHideMs (default 2.2s).

Placement

Fixed to the viewport (default):

createCoffeeCta({ username: "yourname" });

Normal document flow inside an element:

createCoffeeCta({
  username: "yourname",
  anchor: "main",
});

When anchor is set, the host element controls layout and position is ignored.

Scroll target & reverse

Track a nested scroll container instead of the window:

createCoffeeCta({
  username: "yourname",
  scroll: { target: ".article-body" },
});

Reverse mode — full cup at the top, empties as you scroll down:

createCoffeeCta({
  username: "yourname",
  scroll: { reverse: true },
});

Dark theme

Mode Behavior
"auto" Default. Light palette from JS; dark palette via CSS prefers-color-scheme using darkTheme.
"media" JS follows system color scheme; updates when preference changes.
"class" JS follows <html data-theme="dark"> or <html class="dark">.
"off" Light theme always.
createCoffeeCta({
  username: "yourname",
  darkMode: "auto",
  darkTheme: {
    ink: "#e8e8e8",
    chipFg: "#ffffff",
  },
});

For sites that toggle dark mode with a class or data attribute on <html>, use darkMode: "class".

Utility exports

import {
  computeScrollState,
  getScrollMetrics,
  isCtaVisible,
  normalizeBmcUrl,
  resolveScrollTarget,
  resolveUrl,
} from "buy-me-a-coffee-cta";

Helpers for custom scroll integrations, URL normalization, or tests.

Size

Approximate gzipped size: ~7.5 KB JS + ~2.1 KB CSS. The JS bundle includes the inline SVG. Zero runtime dependencies.

Framework integration

Mount after your component loads, call destroy() on unmount, and use updateConfig() when props change. Do not reimplement scroll logic in framework state.

Framework

            

Use the playground to tune options visually and copy a snippet with your custom configuration.

From the repo root, run a framework example locally (packs and installs the library like a consumer would):

pnpm example:react:setup
pnpm example:react:dev

Replace react with vue, solid, angular, svelte, or vanilla for other frameworks.