Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

html datalist for contenteditable (non-input tag)

I would like to know if there's any hackable way anyone might know of which will allow an HTML datalist element to work with a contenteditable element and not with an <input> element.

Example code:

<label>Choose a browser from this list:
  <span contenteditable list="browsers" name="myBrowser">choose</span> 
</label>
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Internet Explorer">
  <option value="Opera">
  <option value="Safari">
  <option value="Microsoft Edge">
</datalist>

fiddle demo

It would seem like it is bound to only with with <input> element. In my situation I have javascript plugin which hides an input field and replaces it with a span, for some "special" things that can only be done with a regular DOM element, such as span. This span is contenteditable and acts is a simulation for the input it replaces, while the input is kept hidden.

like image 422
vsync Avatar asked Jan 14 '17 20:01

vsync


People also ask

How do you use Contenteditable tags in HTML?

To edit the content in HTML, we will use contenteditable attribute. The contenteditable is used to specify whether the element's content is editable by the user or not. This attribute has two values. true: If the value of the contenteditable attribute is set to true then the element is editable.

How the Datalist tag can be used in HTML?

The <datalist> tag specifies a list of pre-defined options for an <input> element. The <datalist> tag is used to provide an "autocomplete" feature for <input> elements. Users will see a drop-down list of pre-defined options as they input data.

How do I make a div not editable?

Try something like this: // Disable all input-like elements in the divs except for the last div $(". divclass:not(:last-child) :input"). attr("disabled", true);

What is meant by Contenteditable in HTML?

The contenteditable attribute is a common attribute. User agents must support this attribute on all HTML elements. The contenteditable attribute is an enumerated attribute whose keywords are the empty string, true , and false . The empty string and the true keyword map to the true state.


1 Answers

As far as I'm aware, there is no standard to apply a <datalist> to random elements with the [contenteditable] attribute, or anything other than a input with the [list] attribute. At best, you'd be beholden to how individual browsers choose to implement that spec.

Obviously, the best medicine is to convert to semantically correct html, but just adding that note for future visitors to do if possible, since that's not your use case.

A possible workaround is to spin up an input element during the focusin event, match the styling of the surrounding span, allow the native browser events to fire, and apply the updated value when the input loses focus.

Here's how that would look in JavaScript:

document.addEventListener('focusin', function (event) {
    if (event.target.matches('[contenteditable]')) {
        var editable = event.target

        // get text
        var text = editable.innerText

        // create input
        var input = document.createElement("input");
        input.type = "text";
        input.className = "editable-mirror";
        input.setAttribute("list", "browsers");
        input.value = text;

        editable.appendChild(input);

        input.focus()
    }
});
document.addEventListener('focusout', function (event) {
    if (event.target.matches('.editable-mirror')) {
        var input = event.target
        var editable = input.closest("[contenteditable]")

        // get text
        var text = input.value;

        // destroy input
        input.parentNode.removeChild(input);

        // apply value
        editable.innerText = text;
    }
});

And some starter styles (although Your Mileage May Vary)

[contenteditable] {
  position: relative;
  border: 1px solid silver;
  padding: 2px 5px;
  display: inline-block;
}

.editable-mirror {
    position: absolute;
    left: -1px;
    top: -1px;
    height: calc(100% + 2px);
    width: calc(100% + 7px);
    padding: 2px 5px;
    margin: 0;
    border: 0;
}

Here's a working demo in Stack Snippets & JSFiddle

document.addEventListener('focusin', function (event) {
	if (event.target.matches('[contenteditable]')) {
        console.log('focused')

        var editable = event.target

        // enter edit mode
        editable.classList.add("editing")
        
        // get text
        var text = editable.innerText

        // create input
        var input = document.createElement("input");
        input.type = "text";
        input.className = "editable-mirror";
        input.setAttribute("list", "browsers");
        input.value = text;

        editable.appendChild(input);

        input.focus()
        
	}
}, false);
document.addEventListener('focusout', function (event) {
    if (event.target.matches('.editable-mirror')) {
        console.log('blur')
        
        var input = event.target
        var editable = input.closest("[contenteditable]")

        // leave edit mode
        editable.classList.remove("editing")

        // get text
        var text = input.value;

        // destroy input
        input.parentNode.removeChild(input);

        // apply value
        editable.innerText = text;
    }
}, false);
[contenteditable] {
  position: relative;
  border: 1px solid silver;
  padding: 2px 5px;
}

.editable-mirror {
    position: absolute;
    left: -1px;
    top: -1px;
    height: calc(100% + 2px);
    width: calc(100% + 12px);
    padding: 2px 5px;
    margin: 0;
    border: 0;
    font: inherit;
}
<h2>Regular - Input + Datalist</h2>
<label>Choose a browser from this list:
<input type="text" list="browsers" placeholder="Edit Me" id="regular" /></label>

<datalist id="browsers">
  <option value="Chrome"/>
  <option value="Firefox"/>
  <option value="Internet Explorer"/>
  <option value="Opera"/>
  <option value="Safari"/>
  <option value="Microsoft Edge"/>
</datalist>

<h2>Workaround - ContentEditable + Datalist</h2>

<label>Choose a browser from this list:
<span contenteditable list="browsers" name="myBrowser">edit me</span></label>
like image 54
KyleMit Avatar answered Oct 12 '22 07:10

KyleMit