Help Beacon

Persistent button opening help options.

?

html

<div class="help-beacon-stage">
  <details class="help-beacon" data-position="bottom-right" style="--accent:#A8E6C1">
    <summary class="help-beacon__button" aria-label="Help">
      ?
      <span class="help-beacon__dot" aria-hidden="true"></span>
    </summary>
    <div class="help-beacon__menu" role="menu">
      <a href="#" role="menuitem">Contact support</a>
      <a href="#" role="menuitem">View documentation</a>
      <a href="#" role="menuitem">Keyboard shortcuts</a>
    </div>
  </details>
</div>
<style>
.help-beacon-stage { position: relative; min-height: 220px; font: 16px/1.5 system-ui, sans-serif; background: #FAF7F2; border-radius: 12px; }
.help-beacon { position: absolute; }
.help-beacon[data-position="bottom-right"] { right: 16px; bottom: 16px; }
.help-beacon[data-position="bottom-left"] { left: 16px; bottom: 16px; }
.help-beacon[data-position="top-right"] { right: 16px; top: 16px; }
.help-beacon__button { list-style: none; width: 46px; height: 46px; border-radius: 50%; background: var(--accent); color: #241430; font: 700 18px system-ui, sans-serif; display: flex; align-items: center; justify-content: center; cursor: pointer; position: relative; box-shadow: 0 8px 18px rgba(36,20,48,.22); }
.help-beacon__button::-webkit-details-marker { display: none; }
.help-beacon__button:focus-visible { outline: 2px solid #241430; outline-offset: 2px; }
.help-beacon__dot { position: absolute; top: 2px; right: 2px; width: 10px; height: 10px; border-radius: 50%; background: #241430; border: 2px solid #FAF7F2; }
.help-beacon__menu { position: absolute; bottom: 54px; right: 0; width: 180px; background: #fff; border-radius: 10px; box-shadow: 0 12px 28px rgba(36,20,48,.24); padding: 8px; display: flex; flex-direction: column; }
.help-beacon[data-position="bottom-left"] .help-beacon__menu { left: 0; right: auto; }
.help-beacon[data-position="top-right"] .help-beacon__menu { bottom: auto; top: 54px; }
.help-beacon__menu a { padding: 8px 10px; border-radius: 6px; font-size: 13.5px; color: #241430; text-decoration: none; }
.help-beacon__menu a:hover, .help-beacon__menu a:focus-visible { background: #24143010; outline: none; }
</style>

tailwind

<div class="relative min-h-[220px] font-sans bg-[#FAF7F2] rounded-xl">
  <details class="help-beacon-tw absolute" data-position="bottom-right" style="--accent:#A8E6C1">
    <summary class="list-none w-[46px] h-[46px] rounded-full flex items-center justify-center font-bold text-lg cursor-pointer relative shadow-[0_8px_18px_rgba(36,20,48,.22)] text-[#241430]" style="background:#A8E6C1" aria-label="Help">
      ?
      <span class="absolute top-0.5 right-0.5 w-2.5 h-2.5 rounded-full bg-[#241430] border-2 border-[#FAF7F2]" aria-hidden="true"></span>
    </summary>
    <div class="help-beacon-tw-menu absolute w-[180px] bg-white rounded-[10px] shadow-[0_12px_28px_rgba(36,20,48,.24)] p-2 flex flex-col" role="menu">
      <a href="#" role="menuitem" class="px-2.5 py-2 rounded-md text-[13.5px] text-[#241430] no-underline hover:bg-[#24143010]">Contact support</a>
      <a href="#" role="menuitem" class="px-2.5 py-2 rounded-md text-[13.5px] text-[#241430] no-underline hover:bg-[#24143010]">View documentation</a>
      <a href="#" role="menuitem" class="px-2.5 py-2 rounded-md text-[13.5px] text-[#241430] no-underline hover:bg-[#24143010]">Keyboard shortcuts</a>
    </div>
  </details>
</div>
<style>
.help-beacon-tw[data-position="bottom-right"] { right: 16px; bottom: 16px; }
.help-beacon-tw[data-position="bottom-left"] { left: 16px; bottom: 16px; }
.help-beacon-tw[data-position="top-right"] { right: 16px; top: 16px; }
.help-beacon-tw[data-position="bottom-right"] .help-beacon-tw-menu, .help-beacon-tw[data-position="bottom-left"] .help-beacon-tw-menu { bottom: 54px; }
.help-beacon-tw[data-position="top-right"] .help-beacon-tw-menu { top: 54px; }
.help-beacon-tw[data-position="bottom-right"] .help-beacon-tw-menu, .help-beacon-tw[data-position="top-right"] .help-beacon-tw-menu { right: 0; }
.help-beacon-tw[data-position="bottom-left"] .help-beacon-tw-menu { left: 0; }
.help-beacon-tw summary::-webkit-details-marker { display: none; }
</style>

react

import { useState } from "react";

export function HelpBeacon({
  label = "Help",
  position = "bottom-right",
  open: initialOpen = false,
  badge = true,
  accent = "#A8E6C1",
}) {
  const [open, setOpen] = useState(initialOpen);
  const corner = {
    "bottom-right": { right: 16, bottom: 16 },
    "bottom-left": { left: 16, bottom: 16 },
    "top-right": { right: 16, top: 16 },
  }[position] ?? {};
  const menuSide = position === "top-right" ? { top: 54 } : { bottom: 54 };
  const menuAlign = position === "bottom-left" ? { left: 0 } : { right: 0 };
  return (
    <div style={{ position: "relative", minHeight: 220, fontFamily: "system-ui, sans-serif", background: "#FAF7F2", borderRadius: 12 }}>
      <div style={{ position: "absolute", ...corner }}>
        <button type="button" aria-label={label} aria-expanded={open} onClick={() => setOpen((o) => !o)}
          style={{ position: "relative", width: 46, height: 46, borderRadius: "50%", background: accent, color: "#241430", fontWeight: 700, fontSize: 18, display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer", border: "none", boxShadow: "0 8px 18px rgba(36,20,48,.22)" }}>
          ?
          {badge && <span style={{ position: "absolute", top: 2, right: 2, width: 10, height: 10, borderRadius: "50%", background: "#241430", border: "2px solid #FAF7F2" }} />}
        </button>
        {open && (
          <div role="menu" style={{ position: "absolute", width: 180, background: "#fff", borderRadius: 10, boxShadow: "0 12px 28px rgba(36,20,48,.24)", padding: 8, display: "flex", flexDirection: "column", ...menuSide, ...menuAlign }}>
            {["Contact support", "View documentation", "Keyboard shortcuts"].map((item) => (
              <a key={item} href="#" role="menuitem" style={{ padding: "8px 10px", borderRadius: 6, fontSize: 13.5, color: "#241430", textDecoration: "none" }}>{item}</a>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}