Embedding and customizing a VueJS component through an iFrame

29 Jul 18 @18:00

Imagine you built a nice booking form in VueJs and now you’d like 3rd parties to customize it and embed it in their own website.

You could leverage the power of Web Components by using the awesome vue-custom-element package. But what if you need to use routes (i.e. vue-router) within your form and use Stripe to authorise payments?

An iFrame would probably work best.

So let’s build a customizable Vue component that is loaded through an iFrame. The flow looks something like the above image.

1. Create a Vue project (in this example, I call it custom-widget)

2. Install vue-router

3. Change your App.vue so that it’s content will contain the content of a route:

// App.vue
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'app',
}
</script>

4. Create a component that will accept inline styles with custom data values, in this case for the background and border color. It has a basic text input for the sake of the example, and alerts its content when blurred.

Note the mounted lifecycle hook is where we get the routes’ query values and change the data accordingly.That’s how we’ll customize our Vue component, by passing our URL values using the iFrame’s src attribute.

// components/CustomComponent.vue
<template>
  <div class="custom-component"
    :style="{
      'background-color': backgroundColor,
      'border-color': borderColor,
      'border-style': 'solid',
      'border-width': '2px',
      'border-radius': '4px',
      'padding': '15px',
      'width': '300px',
      'margin': '0 auto'
    }"
  >
    <input v-model="name" type="text" placeholder="Name" class="input" @blur="showValue">
  </div>
</template>
<script>
export default {
  name: 'CustomComponent',
  data () {
    return {
      name: '',
      backgroundColor: '#EEE',
      borderColor: '#DDD'
    }
  },
  mounted(){
    let q = this.$router.currentRoute.query
    this.backgroundColor = q.backgroundColor
    this.borderColor = q.borderColor
  },
  methods:{
    showValue () {
      alert(this.name)
    }
  }  
}
</script>
<style>
  .input{
    width: 100%;
    padding: 2px 4px;
  }
</style>

5. Now add vue-router to main.js, register it and create a new VueRouter with a single route

// main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import CustomComponent from './components/CustomComponent.vue'
import App from './App.vue'
Vue.use(VueRouter)
const routes = [
  {
    name: 'home',
    path: '/',
    component: CustomComponent,
    props: true
  }
]
Vue.config.productionTip = false
const router = new VueRouter({
  mode: 'history',
  routes: routes
})
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Now when visiting http://localhost:8080/?backgroundColor=green, you can see our component will have a green background:

Now is a matter of adding whatever parameters you wish to customize the component: custom content, styles, attributes, etc.

You could pass a unique ID, identifying a customer and, depending on his plan, allow for a white-label widget or such. Of course all that validation would need to be done on your end.

You could even make a custom widget wizard for your users, generating the embed code instantly:

Voilá, an embeddable, customizable Vue Component!

Links