<div id="app">
  <div class="root">
    <div class="title">
      <h1>Transparent Wrapping example</h1>
    </div>
    <div style="max-width:400px; margin: auto">
    <my-input v-model="text" icon="user"></my-input>
    <br>
    {{text}}
    </div>
    <div>
    </div>
  </div>
</div>
@import url("//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css");

div.root {
    text-align: center;
    padding: 10px;
}

div.title {
    text-align: center;
    background-color: yellow;
    border-style: solid;
    margin-bottom: 2rem;
  }

.container {
  position: relative;
}

.container input {
  padding-left: 30px;
}

input {
  width: 100%;
}

/* style icon */
.container .glyphicon {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  left: 7px;
}
Vue.component('MyInput', {
  name: "MyInput",
  props: {
    icon: String,
    value: String,
  },
  computed: {
    listeners() {
      const listeners = { ...this.$listeners };
      delete listeners["input"];
      return listeners;
    },
    attrs() {
      const attrs = { ...this.$attrs };
      delete attrs["value"];
      return attrs;
    },
    iconClass() {
      return {
        [`glyphicon-${this.icon}`]: this.hasIcon,
      };
    },
    hasIcon() {
      return !!this.icon;
    },
  },

  methods: {
    emitInput(event) {
    this.$emit("input", event.target.value);
    },
  },
  template: `
      <div :class="{ container: hasIcon }">
      <i class="glyphicon" :class="iconClass"></i>
      <input
        v-on="listeners"
        v-bind="attrs"
        v-on:input="emitInput"
        v-bind:value="value"
      />
    </div>
  `,
})

var app = new Vue({
  el: '#app',
  data: {
    text: 'hello'
  },
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js