49

How do I create a custom input text element which enables combining images alongside the text?

Basically those images are emoticons loaded from a CDN.

CLARIFICATION:
What I wish to implement is an <input type="text" /> element which may contain images as part of the input.

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Elimination
  • 2,619
  • 4
  • 22
  • 38
  • 7
    Everything starts with research, then trial and error. Then when you're stuck you come here and mention what you've tried and where it fails. Then people help you. – Wim Ombelets Apr 11 '15 at 15:30
  • I have researched but haven't found a matching result to my need. I am aware of WYSIWYG editors, but digging inside the code may be an overhead. – Elimination Apr 11 '15 at 15:41
  • Do you mean something like http://getbootstrap.com/components/#input-groups? The scroll down to Basic Example – photo_tom Apr 11 '15 at 16:20
  • `display:inline`? is that what you want – Downgoat Apr 11 '15 at 16:20
  • How is the image added in which Format (URL, filename, ID, etc.). Multiple images? What do you need in Server sie, the URL of the image? Binary data? – mgutt Apr 12 '15 at 07:28
  • Basically those images are in png format and loaded from a CDN – Elimination Apr 12 '15 at 07:44
  • Do you just want to show the images inside the input or do you also want to send them to the server? – damian Apr 13 '15 at 15:40
  • 2
    Does this help at all? [Make my textbox understand html img tag](http://stackoverflow.com/questions/15359508/make-my-textbox-understand-html-img-tag) It deals with emojis and what not, but it might point you in the right direction. The most important part is the first paragraph using "contentEditable", [here is the mozilla info](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable) – JasonWilczak Apr 13 '15 at 15:44

5 Answers5

81

Using <img> elements inside of a contenteditable element:

While it's not directly possible to place <img> elements inside of <input type="text" /> elements, you can achieve something similar by using a contenteditable element and placing the <img> element inside of that.

Here is an example using Twitter's Emoji images inside of a contenteditable element:

[contenteditable] {
  border: 1px solid #000;
  line-height: 1.4em;
  -webkit-appearance: textfield;
  appearance: textfield
}
img {
  vertical-align: top;
  max-height: 1.4em;
  max-width: 1.4em;
}
<p>This looks like an <code>input</code> element:</p>

<div contenteditable="true">
  See: <img src="//i.stack.imgur.com/nO2hl.png"/> <img src="//i.stack.imgur.com/iUDpH.png"/> You can even copy/paste these images within this field <img src="//i.stack.imgur.com/QrKSV.png"/>
</div>

You could also add in some JavaScript to dynamically insert the image/icon into the field. If you want to get fancy, you could insert the image at the position of the caret.

document.querySelector('.selectable-icons').addEventListener('click', function(e) {
  if (e.target.tagName.toLowerCase() === 'img') {
    document.querySelector('[contenteditable]').appendChild(e.target.cloneNode(true));
  }
});
[contenteditable] {
  border: 1px solid #000;
  margin: 0.4em 0;
  line-height: 1.4em;
  -webkit-appearance: textfield;
  appearance: textfield;
}
img {
  vertical-align: top;
  max-height: 1.4em;
  max-width: 1.4em;
}
.selectable-icons img {
  cursor: pointer;
}
<p>Just click on an icon to add it.</p>

<div class="custom-input">
  <div class="selectable-icons">
    <img src="//i.stack.imgur.com/nO2hl.png" /><img src="//i.stack.imgur.com/IkjJW.png" /><img src="//i.stack.imgur.com/QrKSV.png" /><img src="//i.stack.imgur.com/sZpOK.png" /><img src="//i.stack.imgur.com/d7HIy.png" /><img src="//i.stack.imgur.com/iUDpH.png" /><img src="//i.stack.imgur.com/IjpTt.png" /><img src="//i.stack.imgur.com/rDCTA.png" /><img src="//i.stack.imgur.com/YtkL1.png" /><img src="//i.stack.imgur.com/wPXCd.png" />
  </div>
  <div contenteditable="true">
    You can type here. Add an icon.
  </div>
</div>

Using unicode inside of an <input> element:

If that's not feasible, you would have to use unicode characters. That's how the Emoji characters work on iOS and Android devices.

For instance, you can use Font Awesome unicode characters within an <input> element. Likewise, you could make your own library of icons/images and represent them with unicode characters:

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>

<p>Font awesome icons (unicode):</p>
<input type="text" class="fa" value="See: &#xf179; &#xf118; &#xf16c;" />


<p>Standard unicode:</p>
<input type="text" value="See: &#x2714; &#x2639; &#x263a;" />
Community
  • 1
  • 1
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
3

It's not posible to render img tag in input, but another simple solution is to place the tag as plain text and display in a container.

Notes:

  1. The example below can be extended to delete an entire tag <.. /> although now is not implemented.

  2. This solution exist because, for some reasons you don't want to use contenteditable described by @josh-crozier,

  3. This solution can make use of a hidden text input and in the display you will see the result using a virtual keyboard (like smartphone keyboard).

In this example you can click emoticons and append them at the carret position and when you click on input your cursor go to the last position of input.

var $emoji = $('.emoji');
var $content = $('.content');
var $display = $('.display');

var initial = 'I know that you are <img class="emoji" src="//i.stack.imgur.com/iUDpH.png"> now';
$content.val(initial);
$display.html($content.val());

$emoji.click(function() {
    var html = $(this)[0].outerHTML;
    insertText(html);
    $display.html($content.val());
});

$content.on('change keyup paste', function(){
    $display.html($content.val());
});

$content.focus(function(){
  this.selectionStart = this.selectionEnd = this.value.length;
});

function insertText(text){
    var cursorPosition = $content.prop('selectionStart');
    var value = $content.val();
    var textBefore = value.substring(0,  cursorPosition );
    var textAfter  = value.substring( cursorPosition, value.length );
    value = textBefore  + text + textAfter;
    $content.val(value);
    $content.prop('selectionStart', value.length);
    $content.focus();
}
.display {
  border: 1px solid #000;
  line-height: 1.4em;
   min-height: 20px;
}
.display img {
  vertical-align: top;
  width: 1.4em
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Select emoji to insert:
<p>
<img class="emoji" src="//i.stack.imgur.com/nO2hl.png"/>
<img class="emoji" src="//i.stack.imgur.com/iUDpH.png"/>
</p>


Result:
<div class="display">
 
</div>
Edit:
<input type="text" class="content" value="" />
adricadar
  • 9,971
  • 5
  • 33
  • 46
2

You would have to write your own WYSIWYG editor for those results. Or you can Look at this previous Question.

In short:

APPROACH: You have to read each and every text entered by user if it matches the pattern of the smile and if the smiley matches then fetch the respective .gif from the images folder.

Please refer following link for a quick start. Replace a list of Emoticons with their pictures

I hope this helps!

Community
  • 1
  • 1
Kleigh
  • 424
  • 3
  • 12
1

Here, i have add emoji anywhere in contenteditable.

[contenteditable=true] {border: 1px solid #000;margin: 0.4em 0;line-height: 1.4em;-webkit-appearance: textfield;appearance: textfield; }
[contenteditable=true]:empty:before {content: attr(placeholder);display: block; /* For Firefox */}
.selectable-icons img { cursor: pointer;vertical-align: top;max-height: 2.4em;max-width: 2.4em; }

<div  id="content" placeholder="Max 10 char with emoji" class="form-control custom_text" contenteditable="true"></div>
    function pasteHtmlAtCaret(html, selectPastedContent) {
                var sel, range;
                if (window.getSelection) {
                    // IE9 and non-IE
                    sel = window.getSelection();
                    if (sel.getRangeAt && sel.rangeCount) {
                        range = sel.getRangeAt(0);
                        range.deleteContents();

                        // Range.createContextualFragment() would be useful here but is
                        // only relatively recently standardized and is not supported in
                        // some browsers (IE9, for one)
                        var el = document.createElement("div");
                        el.innerHTML = html;
                        var frag = document.createDocumentFragment(), node, lastNode;
                        while ( (node = el.firstChild) ) {
                            lastNode = frag.appendChild(node);
                        }
                        var firstNode = frag.firstChild;
                        range.insertNode(frag);

                        // Preserve the selection
                        if (lastNode) {
                            range = range.cloneRange();
                            range.setStartAfter(lastNode);
                            if (selectPastedContent) {
                                range.setStartBefore(firstNode);
                            } else {
                                range.collapse(true);
                            }
                            sel.removeAllRanges();
                            sel.addRange(range);
                        }
                    }
                } else if ( (sel = document.selection) && sel.type != "Control") {
                    // IE < 9
                    var originalRange = sel.createRange();
                    originalRange.collapse(true);
                    sel.createRange().pasteHTML(html);
                    if (selectPastedContent) {
                        range = sel.createRange();
                        range.setEndPoint("StartToStart", originalRange);
                        range.select();
                    }
                }
            }
 // Onclick emoji add in custom text
        $('#select-emoji a').click(function() {
            document.getElementsByClassName('custom_text')[0].focus();
            pasteHtmlAtCaret($(this).html(), false);
            return false;
        });
0

You can also do it this way

.inputimage{
    background:#FFFFFF url(left_arrow.gif) no-repeat 4px 4px;
    padding:4px 4px 4px 22px;
    height:18px;
}​

your input type here with that class

<input type="text" name="sample" class="inputimage">​
Syed Asif
  • 73
  • 2
  • 9
  • OP specifically indicates "which may contain images as part of the input", images being plural, and being part of the input, which this doesn't. This works for one image though, just as a background, but when submitted, the image will NOT be taken into account as part of the input. – c-chavez Apr 25 '18 at 16:18