Update v-html without misbehaving focus on typing VUE JS

I need help,

Requirement

when the user types in an input box I want to highlight the link with blue color if any

My Research

when I dig into it, I realize that without using a contenteditable div it’s not possible to do, also there is no v-model associated with contenteditable div I am manually updating the state.
so far I have this,

 <div id="app"><div class="flex">
          <div class="message" @input="updateHtml" v-html="html" contenteditable="true"></div>
          <br>
          <div class="message">{{ html }}</div>
      </div>
    </div>
        <script>
    let app = new Vue({
      el: '#app',
      data: {
        html: 'some text',
      },
      methods: {
        updateHtml: function(e) {
          this.html = e.target.innerHTML;
        },
        renderHtml: function(){
          this.html += '<img src="https://cdn-images-1.medium.com/max/853/1*FH12a2fX61aHOn39pff9vA.jpeg" alt="" width=200px>';
        }
      }
    });</script>

Issue

every time user types something, the focus is misbehaving which is strange to me, I want v-html to update along with user types @keyup,@keydown also have the same behavior.it works ok on @blur @focusout events, but that’s not what I want

The problem is you’re both setting and overwriting the html at the same time. There’s no point in updating the contenteditable html as it’s already the desired value. You just need to update the output.

Fiddle: https://jsfiddle.net/jamesbrndwgn/xmn2c1u7/

<div id="app">
  <Editor initial-value="Some text" />
</div>
Vue.component('Editor', {
	template: 
  `<div class="flex">
    <div class="message" @input="updateValue" contenteditable="true">{{ initialValue }}</div>
    <br>
    <div class="message" v-html="value"></div>
  </div>`,
  
  props: {
  	initialValue: {
    	type: String,
      default: ''
    }
  },
  
  data () {
    return {
      value: this.initialValue,
    }
  },
  
  methods: {
    updateValue: function(e) {
      this.value = e.target.innerHTML
    }
  }
})

new Vue({
  el: '#app',
});

Hi, @JamesThomson Thank you for your reply, My use case is “when the user types in an input box I want to highlight the link with blue color in the same textbox”, so in that case, we need to update the v-html directive right? referring to your code <div class="message" @input="updateValue" contenteditable="true">{{ initialValue }}</div> didn’t work for me ,because it doesn’t render HTML.Any thoughts on how we can tackle this problem?Thanks.

If you want the contenteditable text to live update with syntax then you’ll need to do more work than just using v-html. You’ll need to store the cursor position so it can be restored properly each time the content updates as well as parse the content so that it renders as expected. Have a look at this vanilla JS codepen to get an idea.

Depending on how far your use case goes, you may want to look at a full fledged editor solution such as TipTap (built on top of ProseMirror) which has solved a lot of the grief of navigating contenteditable and its quirks.

Thank you @JamesThomson, That’s awesome.cherrs :slightly_smiling_face: