The `user-select: none` property displays distinct behavior in Safari

My Goal

I am in the process of creating an input-like content editable div. The idea is to click on tags outside the div and insert them inside the div while still being able to type around these tags.

The Issue and Reproduction Steps

To prevent tag buttons from being selected, I'm using user-select: none (normal and webkit). This works fine in Firefox and Chrome but not in Safari. I've tried adding the -webkit- prefix without success.

Here is a fiddle where you can see the problem in action.

Attempts Made

The main issue was maintaining the caret's position when leaving the content editable div.

I previously experimented with rangy but encountered limitations, especially in Firefox, which had negative effects on UX. You can reference my previous question that led me to explore the user-select: none solution here: Caret disappears in Firefox when saving its position with Rangy

This is how I arrived at the current solution utilizing user-select: none.

Components/JS:

// Vue initialization
new Vue({
  el: "#app",
        data(){
            return {
                // Data properties
            }
        },
        name: 'boolean-input',
        methods: {
            // Methods go here
        },
        props: [ 'first'],
        mounted() {
            this.addPlaceholder()
        }
})

HTML Structure:

<div id="app">
        <!-- HTML structure here -->
</div>

CSS Styling:

    /* CSS styles go here */

Note: Ignore the new Vue initialization code as it's copied from the fiddle link provided for inspection.

Expected Outcome vs Actual Results

In Safari, when clicking a tag after typing a word and moving the caret within that word, the tag should be inserted where the selection was made, but instead, it always gets added at the beginning of the content editable div.

In short, Safari doesn't maintain the caret's position when adding tags, resulting in the tag being placed at the start of the div rather than where the caret was located.

Edit 1: Upon investigation using getSelection(), it seems the offset is consistently 0 due to the div losing focus in Safari. https://i.sstatic.net/IEygT.png

Answer №1

It appears that you have already come across the answer by yourself. The issue at hand seems to be related to timing.

If you switch the event to mousedown, you will notice that the caret position remains intact and the tag is inserted in the appropriate location.

<div id="app">
<div class="input__label-wrap">
<span class="input__label">Search</span>
<div style="user-select: none; -webkit-user-select: none">
<span readonly v-on:mousedown="addBooleanTag(b_button)" v-for="b_button in boolean_buttons" class="boolean-buttons">{{b_button.label}}</span>
</div>
</div> 
<div class="input__boolean input__boolean--no-focus">
<div 
@keydown.enter.prevent
@blur="addPlaceholder"
@keyup="saveCursorLocation($event); fixDelete(); clearHtmlElem($event);"
@input="updateBooleanInput($event); clearHtmlElem($event);"
@paste="pasted"
v-on:click="clearPlaceholder(); saveCursorLocation($event);"
class="input__boolean-content"
ref="divInput"
contenteditable="true">Keywords, boolean search..</div>
</div>
</div>

https://jsfiddle.net/xmuzp20o/

If you prefer not to insert the actual tag on mousedown, consider saving the caret position during that event so that you still have the correct position for the click event.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring Request Parameters in SailsJS

I am facing an issue with logging requests in my Sails app. While I have managed to log the requests successfully, I am unable to log the parameters of the request. myRequestLogger: function(req, res, next) { if (sails.config.environment === & ...

Looking for assistance with finding a specific value in Firestore?

As I venture into using firestore for the first time, I'm in the process of creating a registration page with vue. One crucial step before adding a new user to the database is to validate if the provided username already exists. If it does not exist, ...

Efficiently managing classes with css modules and extractCSS in Nuxt 2

When using Nuxt 2 with CSS modules, I encountered an issue where multiple components resulted in multiple CSS files having the same class. Hello.vue <template> <div :class="$style.title">Hello, World</div> <div :class=&q ...

Displaying multiple arrays using ng-repeat

My task is to display a list organized by date, but the problem is that the list is not sorted and I can't figure out when the date changes. This situation is similar to having the following Json: list = {name: first, date: 2014-05-21}, { {name: sec ...

Tips for sending a state into the gtm.js function?

As an intern at a startup, I am the sole front-end developer responsible for coding a website in Next.js. My boss has requested that I incorporate Google Tag Manager into the project. Following the example provided by Next on their GitHub page, I have succ ...

Is there a way to stop the dropdown from automatically appearing in a DropDownList?

Seeking a solution to use a custom table as the dropdown portion for a DropDownList in my project. My goal is for users to see the custom table when they click on the DropDownList, rather than the default dropdown menu. I expected to be able to achieve th ...

Determine the vertical distance that a div element is currently visible while scrolling

To better understand this concept, please refer to the following fiddle: http://jsfiddle.net/abhicodes/LasxP/ The main goal here is to calculate the visible height of the element with the ID #content-wrapper as the user scrolls. The height of the header ( ...

Building a Database in a Node.js Express Application Using Jade and JavaScript

UPDATE After conducting extensive research, I have discovered that the web application utilizes the node-db-migrate package. Within the migration folder, there are two migrations containing table creations. As I recently git cloned the project, it is evid ...

Various style sheets are used for the production and staging environments

Is there a way to set up different styles for staging in node environments? Let's say I have the following scss files: scss/style.scss scss/theme.scss scss/green.scss After compiling, it gives me: style.scss Now, I'd like to change the style ...

Inquiries regarding JavaScript syntax in a nutshell

I have come across this syntax numerous times, but my attempts to search for it on Google have been unsuccessful. I am hoping to find some help here: <script> (function(){ //code goes here })(); </script> Can someone explain ...

Who is the father of Bootstrap Popover?

I'm currently facing an issue with getting a popover to be placed within a specific element. As of now, the popover is being inserted directly into the <body>, but I require it to be relative to other elements. I have been unable to locate a met ...

Removing elements based on the size of the display

I need assistance with a JavaScript issue. I have a table with 2 rows and 5 columns, each column representing a day of the week with a specific class. The goal is to detect the current day based on the browser's width/height and remove all elements in ...

Break free/Reenter a function within another function

Is there a way to handle validation errors in multiple task functions using TypeScript or JavaScript, and escape the main function if an error occurs? I am working in a node environment. const validate = () => { // Perform validation checks... // ...

Can WebDriverJS be compiled without code minimization using Google Closure Compiler?

I am in need of customizing WebDriverJS to suit my specific requirements. However, I am encountering difficulties with debugging the compiled source code. Having descriptive function names and comments would greatly assist me! Therefore, I am curious to kn ...

Trying to call the Wia class constructor without using the 'new' keyword will result in a TypeError

I'm having trouble running my code from a JSON file, as it's throwing this error message at me: TypeError: Class constructor Wia cannot be invoked without 'new'at Object. (/home/pi/wia-pi-camera/run-camera.js:3:25) 'use strict&apos ...

Utilize the :not() and :hover selectors in Less when styling with CSS

Some of my elements have a specific class called .option, while others also have an additional class named .selected. I want to add some style definition for the :hover state on the .option elements, but only for those without the .selected class. I' ...

Creating a <Box /> component in MaterialUI with styled components is a great way to customize the design and layout of your

@material-ui/styles offers a different way to customize default styles: import React from 'react'; import Box from '@material-ui/core/Box'; import { styled } from '@material-ui/core/styles'; const StyledBox = styled(Box)({ ...

Show a different image with a matching title each time the page loads

I need help creating a JavaScript script that will display a random image from an array along with an associated title each time the page loads. Is there a way to do this without using an onload function placed in the body tag? Currently, my code relies o ...

Accessing dynamic elements in Internet Explorer 7 and 8 using jQuery

I have generated an HTML element dynamically using jQuery. Unfortunately, I am facing difficulties accessing the element utilizing jQuery selectors in IE7/IE8. For example: var id = 45; var $comment = $('#comment-'+id); // dynamically created ...

Execute a function (with arguments) within a v-for loop in Vue.js

Currently, I am attempting to create a select element using Vue.js and Material Design that has 2 levels: categories and items. Each category can contain multiple items which may be selected or not. <md-select v-if="categories.length > 0" name="cate ...