Toolbar appearing for a current selection/context.
Great writing starts with clear design tokens and a consistent voice throughout the document.
<div class="ctb-demo">
<div class="ctb-wrap">
<p class="ctb-text">Great writing starts with clear <span class="ctb-selection">design tokens</span> and a consistent voice throughout the document.</p>
<div class="ctb-toolbar ctb-toolbar--above ctb-toolbar--dark" role="toolbar" aria-label="Text formatting">
<button type="button" class="ctb-btn" aria-label="Bold" style="color:#E8A020;"><strong>B</strong></button>
<button type="button" class="ctb-btn" aria-label="Italic" style="color:#E8A020;"><em>I</em></button>
<span class="ctb-divider" aria-hidden="true"></span>
<button type="button" class="ctb-btn" aria-label="Add link" style="color:#E8A020;">
<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><path d="M8.5 11.5 11.5 8.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M9.5 6.5 11 5a2.5 2.5 0 0 1 3.5 3.5L13 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M10.5 13.5 9 15a2.5 2.5 0 0 1-3.5-3.5L7 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</button>
<button type="button" class="ctb-btn" aria-label="Add comment" style="color:#E8A020;">
<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><path d="M3 4.5h14v9H8l-3 3v-3H3z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg>
</button>
</div>
</div>
</div>
<style>
.ctb-demo { display: grid; place-items: center; min-height: 260px; border-radius: 12px; padding: 24px; box-sizing: border-box; }
.ctb-wrap { position: relative; max-width: 420px; font: 15px/1.7 system-ui, sans-serif; color: #241430; }
.ctb-text { margin: 0; }
.ctb-selection { background: #BFD9F255; border-radius: 3px; padding: 0 2px; }
.ctb-toolbar { position: absolute; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 4px; padding: 6px 8px; border-radius: 10px; box-shadow: 0 10px 24px rgba(36,20,48,.28); }
.ctb-toolbar--above { bottom: calc(100% + 10px); }
.ctb-toolbar--below { top: calc(100% + 10px); }
.ctb-toolbar--light { background: #FAF7F2; }
.ctb-toolbar--dark { background: #241430; }
.ctb-toolbar--brand { background: #D9C8F0; }
.ctb-btn { background: none; border: none; cursor: pointer; font: 600 13px system-ui, sans-serif; padding: 5px 8px; border-radius: 6px; display: grid; place-items: center; }
.ctb-btn:hover, .ctb-btn:focus-visible { background: rgba(255,255,255,.16); outline: none; }
.ctb-divider { width: 1px; height: 16px; background: currentColor; opacity: .25; }
</style><div class="grid place-items-center min-h-[260px] rounded-xl p-6 box-border">
<div class="relative max-w-[420px] font-sans text-[15px] leading-[1.7] text-[#241430]">
<p class="m-0">Great writing starts with clear <span class="bg-[#BFD9F2]/30 rounded-[3px] px-0.5">design tokens</span> and a consistent voice throughout the document.</p>
<div role="toolbar" aria-label="Text formatting" class="ctb-tw ctb-tw--above ctb-tw--dark absolute left-1/2 -translate-x-1/2 flex items-center gap-1 px-2 py-1.5 rounded-[10px] shadow-2xl">
<button type="button" aria-label="Bold" class="bg-transparent border-none cursor-pointer font-semibold text-[13px] px-2 py-1 rounded-md grid place-items-center" style="color:#E8A020;"><strong>B</strong></button>
<button type="button" aria-label="Italic" class="bg-transparent border-none cursor-pointer font-semibold text-[13px] px-2 py-1 rounded-md grid place-items-center" style="color:#E8A020;"><em>I</em></button>
<span aria-hidden="true" class="w-px h-4 bg-current opacity-25"></span>
<button type="button" aria-label="Add link" class="bg-transparent border-none cursor-pointer px-2 py-1 rounded-md grid place-items-center" style="color:#E8A020;">
<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><path d="M8.5 11.5 11.5 8.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M9.5 6.5 11 5a2.5 2.5 0 0 1 3.5 3.5L13 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M10.5 13.5 9 15a2.5 2.5 0 0 1-3.5-3.5L7 10" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</button>
<button type="button" aria-label="Add comment" class="bg-transparent border-none cursor-pointer px-2 py-1 rounded-md grid place-items-center" style="color:#E8A020;">
<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><path d="M3 4.5h14v9H8l-3 3v-3H3z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg>
</button>
</div>
</div>
</div>
<style>
.ctb-tw--above { bottom: calc(100% + 10px); }
.ctb-tw--below { top: calc(100% + 10px); }
.ctb-tw--light { background: #FAF7F2; }
.ctb-tw--dark { background: #241430; }
.ctb-tw--brand { background: #D9C8F0; }
</style>export function ContextualToolbar({
selectedText = "design tokens",
label = "Text formatting",
variant = "dark",
accent = "#E8A020",
placement = "above",
visible = true,
}) {
const bg = { light: "#FAF7F2", dark: "#241430", brand: "#D9C8F0" }[variant] ?? "#241430";
const pos = placement === "below" ? { top: "calc(100% + 10px)" } : { bottom: "calc(100% + 10px)" };
return (
<div style={{ display: "grid", placeItems: "center", minHeight: 260, borderRadius: 12, padding: 24, boxSizing: "border-box" }}>
<div style={{ position: "relative", maxWidth: 420, font: "15px/1.7 system-ui, sans-serif", color: "#241430" }}>
<p style={{ margin: 0 }}>
Great writing starts with clear{" "}
<span style={{ background: "#BFD9F255", borderRadius: 3, padding: "0 2px" }}>{selectedText}</span>{" "}
and a consistent voice throughout the document.
</p>
{visible && (
<div role="toolbar" aria-label={label} style={{ position: "absolute", left: "50%", transform: "translateX(-50%)", display: "flex",
alignItems: "center", gap: 4, padding: "6px 8px", borderRadius: 10, boxShadow: "0 10px 24px rgba(36,20,48,.28)", background: bg, ...pos }}>
<button type="button" aria-label="Bold" style={{ background: "none", border: "none", cursor: "pointer", fontWeight: 600, fontSize: 13, padding: "5px 8px", borderRadius: 6, color: accent }}><strong>B</strong></button>
<button type="button" aria-label="Italic" style={{ background: "none", border: "none", cursor: "pointer", fontWeight: 600, fontSize: 13, padding: "5px 8px", borderRadius: 6, color: accent }}><em>I</em></button>
<span aria-hidden="true" style={{ width: 1, height: 16, background: "currentColor", opacity: .25 }} />
<button type="button" aria-label="Add link" style={{ background: "none", border: "none", cursor: "pointer", padding: "5px 8px", borderRadius: 6, color: accent, display: "grid", placeItems: "center" }}>
<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true">
<path d="M8.5 11.5 11.5 8.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
<path d="M9.5 6.5 11 5a2.5 2.5 0 0 1 3.5 3.5L13 10" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
<path d="M10.5 13.5 9 15a2.5 2.5 0 0 1-3.5-3.5L7 10" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
</svg>
</button>
<button type="button" aria-label="Add comment" style={{ background: "none", border: "none", cursor: "pointer", padding: "5px 8px", borderRadius: 6, color: accent, display: "grid", placeItems: "center" }}>
<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true">
<path d="M3 4.5h14v9H8l-3 3v-3H3z" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" />
</svg>
</button>
</div>
)}
</div>
</div>
);
}