How to Trigger a JavaScript Function When Text is Selected and Find Its Position on the Page
Text selection is a fundamental user interaction on the web. Whether you’re building a note-taking app, a content editor, or a tool that enhances readability (like a translator or summarizer), triggering actions when text is selected can significantly improve user experience.
In this blog, we’ll explore how to detect when a user selects text on a webpage using JavaScript, retrieve the selected text, and accurately determine its position (coordinates) on the page. We’ll cover core concepts like the Selection API, event listeners, and DOM positioning, with practical examples to help you implement these features in your projects.
Table of Contents#
- Understanding Text Selection in JavaScript
- Triggering a Function When Text is Selected
- Finding the Position of Selected Text
- Advanced Use Cases
- Common Pitfalls and Solutions
- Conclusion
- References
1. Understanding Text Selection in JavaScript#
Before diving into triggering functions, let’s first understand how JavaScript represents text selections. The Selection API provides access to the user’s text selection, allowing you to read, modify, or react to selections.
Key Concepts:#
window.getSelection(): Returns aSelectionobject representing the user’s current selection.SelectionObject: Contains properties likeanchorNode(start of the selection),focusNode(end of the selection), and methods to manipulate the selection.RangeObject: ASelectiontypically contains one or moreRangeobjects (most browsers support a single range by default). ARangerepresents a contiguous segment of the document.
Basic Example: Getting Selected Text#
To retrieve the selected text, you can use window.getSelection().toString():
// Get the selected text
const selection = window.getSelection();
const selectedText = selection.toString().trim();
console.log("Selected Text:", selectedText); // Logs the selected text if any2. Triggering a Function When Text is Selected#
To run a function when the user selects text, we need to listen for selection-related events. Two common approaches are:
Approach 1: Using the selectionchange Event#
The selectionchange event fires whenever the user’s selection changes (e.g., selecting, deselecting, or modifying text). It’s the most reliable way to detect selection updates.
Example:#
// Listen for selection changes
document.addEventListener('selectionchange', handleSelectionChange);
function handleSelectionChange() {
const selection = window.getSelection();
const selectedText = selection.toString().trim();
if (selectedText) {
console.log("User selected text:", selectedText);
// Call your custom function here
yourCustomFunction(selectedText);
} else {
console.log("No text selected.");
// Handle deselection (e.g., hide tooltips)
}
}
function yourCustomFunction(text) {
// Your logic here (e.g., highlight, translate, or analyze text)
alert(`Selected: ${text}`);
}Approach 2: Using mouseup Event (Legacy)#
Older tutorials sometimes use the mouseup event (fired when the mouse is released) to check for selections. However, this misses selections made with keyboard shortcuts (e.g., Shift+Arrow keys). Use selectionchange instead for broader coverage.
Example (for reference only):#
// Less reliable: Listens for mouse release
document.addEventListener('mouseup', () => {
const selection = window.getSelection();
const selectedText = selection.toString().trim();
if (selectedText) {
console.log("Mouse released with selection:", selectedText);
}
});Why selectionchange is better: It works for keyboard selections, touch selections (mobile), and dynamic content updates, making it more robust.
3. Finding the Position of Selected Text#
Once you’ve detected a selection, you may want to know its on-page coordinates (e.g., to show a tooltip near the selection). This requires getting the Range object from the Selection and using getBoundingClientRect().
Step 1: Get the Range from the Selection#
A Selection object contains ranges. For most cases, we only need the first range:
const selection = window.getSelection();
if (selection.rangeCount > 0) {
const range = selection.getRangeAt(0); // Get the first (and only) range
}Step 2: Get Position with getBoundingClientRect()#
The Range object has a method getBoundingClientRect(), which returns a DOMRect object describing the selection’s position relative to the viewport.
DOMRect Properties:#
top: Distance from the top of the viewport.left: Distance from the left of the viewport.bottom,right: Opposite edges.width,height: Dimensions of the selection.
Example: Get Selection Coordinates#
function getSelectionPosition() {
const selection = window.getSelection();
if (selection.rangeCount === 0) return null; // No selection
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect(); // Position relative to viewport
// Convert viewport-relative to page-relative coordinates
const position = {
top: rect.top + window.scrollY, // Add scroll offset for page position
left: rect.left + window.scrollX,
width: rect.width,
height: rect.height
};
return position;
}
// Use in selectionchange event
document.addEventListener('selectionchange', () => {
const position = getSelectionPosition();
if (position) {
console.log("Selection Position (Page):", position);
// Example: Log top/left coordinates
console.log(`Top: ${position.top}px, Left: ${position.left}px`);
}
});4. Advanced Use Cases#
Now that you can detect selections and their positions, let’s explore practical applications.
Example 1: Show a Tooltip Near Selected Text#
Dynamically create a tooltip and position it near the selected text:
let tooltip;
document.addEventListener('selectionchange', () => {
const selection = window.getSelection();
const selectedText = selection.toString().trim();
const position = getSelectionPosition();
// Remove existing tooltip if no selection
if (!selectedText && tooltip) {
tooltip.remove();
tooltip = null;
return;
}
// Create tooltip if selection exists
if (selectedText && position) {
if (!tooltip) {
tooltip = document.createElement('div');
tooltip.style.cssText = `
position: absolute;
background: #333;
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 14px;
pointer-events: none;
z-index: 1000;
`;
document.body.appendChild(tooltip);
}
// Update tooltip text and position
tooltip.textContent = `Selected: ${selectedText.substring(0, 30)}...`; // Truncate long text
tooltip.style.top = `${position.top - 40}px`; // Position above the selection
tooltip.style.left = `${position.left}px`;
}
});Example 2: Highlight Selected Text#
Use the Range API to wrap selected text in a highlight span:
function highlightSelection() {
const selection = window.getSelection();
if (!selection.rangeCount) return;
const range = selection.getRangeAt(0);
const span = document.createElement('span');
span.style.backgroundColor = 'yellow';
// Surround the range with the span
try {
range.surroundContents(span);
} catch (e) {
console.error("Cannot highlight non-contiguous selections:", e);
}
// Clear the selection after highlighting
selection.removeAllRanges();
}
// Trigger highlight on button click (or in selectionchange)
document.getElementById('highlight-btn').addEventListener('click', highlightSelection);5. Common Pitfalls and Solutions#
Pitfall 1: Selections in Iframes#
The selectionchange event and window.getSelection() only work for the current document. For selections in iframes, you must listen to the iframe’s contentDocument:
const iframe = document.querySelector('iframe');
iframe.contentDocument.addEventListener('selectionchange', () => {
const selection = iframe.contentWindow.getSelection();
// Process selection in iframe
});Pitfall 2: Empty Selections#
Always check if selectedText is non-empty before processing to avoid errors:
if (selectedText.trim().length > 0) {
// Proceed only if text is selected
}Pitfall 3: Multiple Ranges#
Most browsers support only single-range selections by default. To handle edge cases, check selection.rangeCount:
if (selection.rangeCount > 0) {
const range = selection.getRangeAt(0); // Get the first range
}6. Conclusion#
Triggering functions on text selection and finding its position is powerful for building interactive UIs. By combining the selectionchange event, Selection API, and getBoundingClientRect(), you can create features like tooltips, highlights, and context-aware tools.
Key takeaways:
- Use
document.addEventListener('selectionchange', ...)to detect selections. - Retrieve selected text with
window.getSelection().toString(). - Get positions with
Range.getBoundingClientRect()and adjust for scroll offsets. - Handle edge cases like iframes and empty selections.
7. References#
- MDN: Selection API
- MDN: Range.getBoundingClientRect()
- MDN: selectionchange Event
- Can I Use: Selection API (supported in all modern browsers).