Overview
When users select text on mobile devices, browsers display a context menu or toolbar with actions like Copy, Paste, and Share. These toolbars vary significantly across browsers, operating systems, and devices. Understanding these differences is crucial for building rich text editors that work well on mobile.
Note: Mobile selection toolbars are system-level UI elements that cannot be fully customized. However, you can detect selection changes and show your own custom toolbar alongside or instead of the default one.
iOS Safari Toolbar
iOS Safari displays a toolbar above the selected text with standard actions.
Default Menu Items
Basic Actions
- Copy: Copies selected text to clipboard
- Select All: Selects all text in the contenteditable element
- Paste: Pastes from clipboard (if clipboard has content)
Formatting Options (contenteditable only)
- Bold: Applies bold formatting to selected text
- Italic: Applies italic formatting to selected text
- Underline: Applies underline formatting to selected text
- Strikethrough: Applies strikethrough formatting (may not appear in all versions)
⚠️ Formatting options only appear in contenteditable elements, not in regular text inputs.
iOS-Specific Features
- Look Up: Dictionary lookup (iOS feature)
- Share: iOS share sheet
- Define: Dictionary definition
⚠️ iOS-Specific Behavior
iOS Safari characteristics:
- Toolbar appears above selection (may overlap content)
- Menu items may vary based on selection context
- Cannot be fully disabled or customized
- May interfere with custom toolbars
- Selection handles are small and may be difficult to use
Android Chrome Toolbar
Android Chrome displays a toolbar with actions that may vary by Android version and device manufacturer.
Default Menu Items
Basic Actions
- Copy: Copies selected text to clipboard
- Select All: Selects all text in the contenteditable element
- Paste: Pastes from clipboard
- Cut: Cuts selected text (may appear in some contexts)
Formatting Options (contenteditable only)
- Bold: Applies bold formatting to selected text
- Italic: Applies italic formatting to selected text
- Underline: Applies underline formatting to selected text
- Strikethrough: Applies strikethrough formatting (varies by Android version)
⚠️ Formatting options only appear in contenteditable elements, not in regular text inputs.
Android-Specific Features
- Web Search: Searches selected text (Android feature)
- Share: Android share menu
- Translate: Google Translate (if available)
⚠️ Android-Specific Behavior
Android Chrome characteristics:
- Toolbar position may vary (above or below selection)
- Menu items differ by Android version and manufacturer
- Samsung devices may have additional options
- Selection handles may overlap with content
- Virtual keyboard may interfere with toolbar visibility
Browser-Specific Differences
Toolbar Comparison
| Browser | Position | Menu Items | Customizable |
|---|---|---|---|
| iOS Safari | Above selection | Copy, Select All, Paste, Bold, Italic, Underline, Look Up, Share, Define | No (system-level) |
| Android Chrome | Above or below | Copy, Select All, Paste, Cut, Bold, Italic, Underline, Web Search, Share, Translate | No (system-level) |
| Android Firefox | Above selection | Copy, Select All, Paste, Bold, Italic, Underline, Share | No (system-level) |
| Samsung Internet | Above selection | Copy, Select All, Paste, Bold, Italic, Underline, Share, Samsung-specific options | No (system-level) |
⚠️ Critical: Toolbar Cannot Be Fully Disabled
System-level toolbars cannot be completely disabled:
- CSS
-webkit-touch-callout: nonemay prevent some toolbars on iOS, but not all - Setting
user-select: noneprevents selection entirely - Preventing
contextmenuevent may not work on all browsers - Best approach: Show custom toolbar alongside default, or design UI to work with default toolbar
Select All Behavior
The "Select All" option in mobile toolbars selects all content within the contenteditable element, not just the visible text.
- Scope: Selects all text in the contenteditable element, including nested elements
- Behavior: Creates a Range that spans from first to last text node
- Cross-element: May select across multiple block elements (p, div, etc.)
- Browser differences: Some browsers may include or exclude certain elements differently
Note: "Select All" behavior may differ from desktop keyboard shortcut (Cmd/Ctrl + A). On mobile, it's triggered through the toolbar menu, which may have different behavior than the keyboard shortcut.
OS & Device-Specific Differences
iOS
- iOS Version: Menu items and formatting options may differ between iOS versions
- iPad vs iPhone: Toolbar behavior and formatting options may differ on larger screens
- Accessibility: VoiceOver may affect toolbar interaction and menu item availability
- Split View: Toolbar positioning may change in split-screen mode
- Formatting: iPad may show more formatting options than iPhone
Android
- Android Version: Menu items and formatting options vary by Android version (e.g., Android 10 vs Android 13)
- Manufacturer: Samsung, Xiaomi, etc. may add custom menu items or modify formatting options
- Device Size: Tablet vs phone may have different toolbar layouts and formatting options
- Custom ROMs: Custom Android ROMs may modify toolbar behavior and menu items
- Keyboard Apps: Some keyboard apps (Gboard, Samsung Keyboard) may add their own formatting options
Implementing Custom Toolbars
While you cannot fully replace the system toolbar, you can detect selection changes and show your own custom toolbar. Here are common approaches:
// Show custom toolbar on selection
let customToolbar = null;
document.addEventListener('selectionchange', () => {
const selection = window.getSelection();
if (selection.rangeCount > 0 && !selection.isCollapsed) {
const range = selection.getRangeAt(0);
const rects = range.getClientRects();
if (rects.length > 0) {
const rect = rects[0];
showCustomToolbar(rect);
}
} else {
hideCustomToolbar();
}
});
function showCustomToolbar(rect) {
if (!customToolbar) {
customToolbar = document.createElement('div');
customToolbar.className = 'custom-toolbar';
customToolbar.innerHTML = `
<button onclick="formatBold()">Bold</button>
<button onclick="formatItalic()">Italic</button>
<button onclick="copyText()">Copy</button>
`;
document.body.appendChild(customToolbar);
}
// Position toolbar above selection
customToolbar.style.display = 'block';
customToolbar.style.position = 'fixed';
customToolbar.style.top = (rect.top - 50) + 'px';
customToolbar.style.left = rect.left + 'px';
}
function hideCustomToolbar() {
if (customToolbar) {
customToolbar.style.display = 'none';
}
}⚠️ Positioning Challenges
Toolbar positioning is complex on mobile:
- System toolbar may overlap your custom toolbar
- Virtual keyboard may push toolbars off-screen
- Viewport changes (zoom, rotation) affect positioning
- Multi-line selections require different positioning logic
- Use
getClientRects()for accurate selection position
Best Practices
- Position above selection: Place custom toolbar above selection to avoid overlap with system toolbar
- Hide on scroll: Hide custom toolbar when user scrolls to avoid UI clutter
- Touch-friendly buttons: Make toolbar buttons large enough for touch (minimum 44x44px)
- Handle viewport changes: Reposition toolbar on orientation change or keyboard show/hide
- Test on real devices: Emulators may not accurately represent toolbar behavior
Disabling Default Toolbar (Limited)
Attempting to disable the default toolbar has limited success. Here are approaches that may work in some browsers:
// Disable default selection toolbar (may not work in all browsers)
element.style.userSelect = 'none'; // Prevents selection entirely
// Or allow selection but try to prevent toolbar
element.addEventListener('contextmenu', (e) => {
e.preventDefault(); // May prevent some toolbars
});
// CSS approach
// .contenteditable {
// -webkit-user-select: text;
// -webkit-touch-callout: none; /* iOS Safari - disable callout menu */
// user-select: text;
// }⚠️ Limitations
These methods have limitations:
-webkit-touch-callout: noneonly works on iOS Safari, and may not prevent all toolbars- Preventing
contextmenumay not work on all mobile browsers - Setting
user-select: noneprevents all selection, which breaks text editing - Best practice: Design your UI to work with the default toolbar, or show custom toolbar alongside it
Mobile Detection
Detect mobile devices to conditionally show custom toolbars or handle mobile-specific behavior:
// Detect mobile device
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// Detect touch capability
function isTouchDevice() {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
}
// Use for conditional toolbar behavior
if (isMobile() || isTouchDevice()) {
// Show custom toolbar or handle mobile-specific behavior
}Selection Handle Issues
⚠️ Mobile Selection Handles
Selection handles are problematic on mobile:
- Size: Handles are small and difficult to grab with fingers
- Overlap: Handles may overlap with content or toolbar
- Precision: Touch input is less precise than mouse, making fine adjustments difficult
- Scrolling: Dragging handles may trigger page scroll instead of selection adjustment
- Keyboard: Virtual keyboard may cover handles or toolbar
Consider providing alternative selection methods for mobile, such as tap-to-select-word or long-press-to-select-sentence, to improve usability.
Virtual Keyboard Interference
⚠️ Keyboard and Toolbar Conflicts
Virtual keyboard may interfere with toolbars:
- Keyboard may push toolbar off-screen
- Toolbar may appear behind keyboard
- Selection handles may be hidden by keyboard
- Viewport height changes when keyboard appears/disappears
- Reposition toolbar when keyboard visibility changes
Testing Recommendations
- Test on real devices: Emulators may not accurately show toolbar behavior
- Test multiple browsers: Safari, Chrome, Firefox, Samsung Internet
- Test different OS versions: iOS 15+, iOS 16+, Android 10+, Android 13+
- Test different devices: iPhone, iPad, various Android phones and tablets
- Test with virtual keyboard: Ensure toolbars work when keyboard is visible
- Test orientation changes: Portrait vs landscape may affect toolbar positioning
- Test with different keyboard apps: Gboard, Samsung Keyboard, iOS keyboard