About this snippet

Enhance reading experiences with a floating text selection toolbar. Whenever users highlight text, a beautiful Medium-style popup appears dynamically right above their cursor.

Size
3.2 KB
Uses
HTML, CSS, JavaScript
Loads
Nothing external
Views
259

Collections

<div class="article-container">
  <h2>Select any text below</h2>
  <p class="article-text">
    The future of web design focuses heavily on highly polished micro-interactions. When you build interfaces that respond naturally to user intent, you create an experience that feels alive. Highlighting text is a core browser feature, but enhancing it with a native-feeling context menu elevates the entire application to an enterprise standard.
  </p>
</div>

<div class="selection-toolbar" id="text-toolbar">
  <button class="tool-action">Highlight</button>
  <button class="tool-action">Share</button>
  <button class="tool-action">Copy</button>
</div>
*, *::before, *::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  margin: 0;
  background: #f8fafc;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 20px;
}

.article-container {
  max-width: 600px;
  background: #ffffff;
  padding: 50px;
  border-radius: 20px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
}

.article-container h2 {
  margin: 0 0 20px 0;
  color: #0f172a;
}

.article-text {
  font-size: 1.125rem;
  line-height: 1.8;
  color: #334155;
  margin: 0;
}

::selection {
  background: #dbeafe;
  color: #1e3a8a;
}

.selection-toolbar {
  position: absolute;
  background: #0f172a;
  padding: 6px;
  border-radius: 12px;
  display: flex;
  gap: 4px;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  /* Start hidden safely */
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px) translateX(-50%);
  transition: opacity 0.2s, transform 0.2s, visibility 0.2s;
}

.selection-toolbar.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) translateX(-50%);
}

.selection-toolbar::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-width: 6px;
  border-style: solid;
  border-color: #0f172a transparent transparent transparent;
}

.tool-action {
  background: transparent;
  color: #f8fafc;
  border: none;
  padding: 8px 16px;
  border-radius: 8px;
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
}

.tool-action:hover {
  background: #334155;
}
const toolbar = document.getElementById("text-toolbar");

document.addEventListener("mouseup", function() {
  /* Using native window selection safely */
  const selection = window.getSelection();
  const text = selection.toString().trim();
  
  if (text.length > 0) {
    /* Get precise coordinates of the highlighted text */
    const range = selection.getRangeAt(0);
    const rect = range.getBoundingClientRect();
    
    /* Position the toolbar exactly above the text center */
    const top = rect.top + window.scrollY - 50;
    const left = rect.left + window.scrollX + (rect.width / 2);
    
    toolbar.style.top = top + "px";
    toolbar.style.left = left + "px";
    toolbar.classList.add("is-visible");
  } else {
    toolbar.classList.remove("is-visible");
  }
});

/* Hide when user clicks away */
document.addEventListener("mousedown", function(e) {
  if (e.target !== toolbar && !toolbar.contains(e.target)) {
    toolbar.classList.remove("is-visible");
  }
});
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save