Skip to content

Instantly share code, notes, and snippets.

@padcom
Last active February 10, 2022 16:50
Show Gist options
  • Save padcom/872cddfe13d19b56295769944eed226b to your computer and use it in GitHub Desktop.
Save padcom/872cddfe13d19b56295769944eed226b to your computer and use it in GitHub Desktop.
Example completely custom Vue 3 component with contenteditable and v-model support
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
box-sizing: border-box;
}
.example {
background-color: lightgray;
margin-bottom: 10px;
}
.example[contenteditable] {
min-height: 100px;
padding: 2px;
border: solid 2px transparent;
}
.example[contenteditable]:focus {
border: dashed 2px black;
outline: none;
}
</style>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3.2.29/dist/vue.esm-browser.prod.js"
}
}
</script>
</head>
<body>
<div id="app">
<example-abc v-model="message" v-focus></example-abc>
{{ message }}
</div>
<template id="example">
<div class="example" tabindex="0" contenteditable="plaintext-only" @input="$emit('update:modelValue', $event.target.innerText)">
{{ value }}
</div>
</template>
<script type="module">
import { createApp, defineComponent } from 'vue'
const Example = defineComponent({
template: '#example',
props: [ 'modelValue' ],
events: [ 'update:modelValue' ],
data() {
// Working with the initial value because when the div's content changes
// the entire value is sent back over to the parent and then re-rendered
// in this component. This messes up a lot of things like new lines,
// copy/pasting and others.
return {
value: this.modelValue
}
},
watch: {
modelValue(value) {
this.value = value
},
},
})
const app = createApp({
data() {
return {
message: 'Hello, world!'
}
},
})
app.directive('focus', {
mounted(el) {
el.focus()
}
})
app.component('example-abc', Example)
app.mount('#app')
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment