SlideShare a Scribd company logo
Vue.js Renderless Components
It’s like advanced internet Legos!
ToThePoint STS / Lars van Herk / 3 june, 2019
1. Build a standard, feature-rich base component
2. Separate the view from the logic
3. Slap it into a publishable library
WHAT’CHA GONNA DO?
INTRODUCTION
We’re gonna do some Vue.
WHY SO COMPLICATED?
INTRODUCTION
Every app works differently
- “Our date pickers don’t look like that!”
- Tweaking a prebuilt component’s layout is
hard or impossible
- Either accept it, or rebuild it
WHAT DO WE NEED FOR THIS?
INTRODUCTION
Slots. Scoped Slots.
https://vuejs.org/v2/guide/components-slots.html
<template>
<section class="my-alert">
<slot name="title">
<h1>This will be the default title!</h1>
</slot>
<slot v-bind:person="person">
Hello, {{ person.name }}!
</slot>
</section>
</template>
<template>
<div id="app">
<my-alert :person="outerPerson">
<template v-slot:title>
<h1>I'm going to replace the default!</h1>
</template>
</my-alert>
</div>
</template>
<template>
<section class="my-alert">
<h1>I'm going to replace the default!</h1>
Hello, Bobby!
</section>
</template>
MyAlert.vue
App.vue
Rendered Output
INTRODUCTION
RENDERING ALL THE THINGS!
INTRODUCTION
- Template part of SFC isn’t required!
- Can be replaced with a render function
- Also known as the ‘h(…)’ function
- ‘render()’: available in ‘script’ section
THE STARTING BLOCKS
BUILDING THE COMPONENT
1. Build the basic component
2. Split logic from rendering
3. Use our old view as a default
BRACE YOURSELVES, CODE AHOY!
BUILDING THE COMPONENT
<script>
export default {
data: () => ({
user: {
firstName: '',
lastName: ''
}
}),
watch: {
user: {
handler (val) {
this.$emit('input:user', val);
},
deep: true
}
},
methods: {
insertBob () {
this.user = {
firstName: 'Bob',
lastName: 'Marley'
};
}
}
};
</script>
<template>
<section class="my-user">
<h1>My User</h1>
<div class="my-user__input">
<label for="firstname">First Name</label>
<input type="text" id="firstname" v-model="user.firstName">
</div>
<div class="my-user__input">
<label for="lastname">Last Name</label>
<input type="text" id="lastname" v-model="user.lastName">
</div>
<button @click="insertBob()">Insert Bob</button>
</section>
</template>
BUILDING THE COMPONENT <script>
export default {
data: () => ({
scopeData: {
user: {
firstName: '',
lastName: ''
}
}
}),
watch: {
'scopeData.user': { … }
},
methods: {
updateUser (data) { … },
insertBob () { … }
},
render () {
return this.$scopedSlots.default({
// TODO
});
}
};
</script>
<script>
export default {
data: () => ({
user: {
firstName: '',
lastName: ''
}
}),
watch: {
user: {
handler (val) {
this.$emit('input:user', val);
},
deep: true
}
},
methods: {
insertBob () {
this.user = {
firstName: 'Bob',
lastName: 'Marley'
};
}
}
};
</script>
BUILDING THE COMPONENT
<script>
export default {
data: () => ({
scopeData: {
user: {
firstName: '',
lastName: ''
}
}
}),
…
render () {
return this.$scopedSlots.default({
// DATA
...this.scopeData,
// ACTIONS
updateUser: this.updateUser,
insertBob: this.insertBob
});
}
};
</script>
WE’RE ALMOST THERE 🎉
BUILDING THE COMPONENT
1. Build the basic component
2. Split logic from rendering
3. Use our old view as a default
BUILDING THE COMPONENT
<template>
<section class="my-user">
<h1>My User</h1>
<div class="my-user__input">
<label for="firstname">First Name</label>
<input
type="text" id="firstname"
v-model="user.firstName">
</div>
<div class="my-user__input">
<label for="lastname">Last Name</label>
<input
type="text" id="lastname"
v-model="user.lastName">
</div>
<button @click="insertBob()">Insert Bob</button>
</section>
</template>
<template>
<section class="my-user">
<my-user-rl @input:user="$emit('input:user', $event)">
<template
v-slot:default="{
user,
updateUser,
insertBob
}">
<section>
<h1>My User</h1>
<div class="my-user__input">
<label for="firstname">First Name</label>
<input type="text" id="firstname"
:value="user.firstName"
@input="updateUser({ firstName: $event.target.value })" />
</div>
<div class="my-user__input">
<label for="lastname">Last Name</label>
<input type="text" id="lastname"
:value="user.lastName"
@input="updateUser({ lastName: $event.target.value })" />
</div>
<button @click="insertBob()">Insert Bob</button>
</section>
</template>
</my-user-rl>
</section>
</template>
BUILDING THE COMPONENT
<template>
<section class="my-user">
<my-user-rl @input:user="$emit('input:user', $event)">
<template
v-slot:default="{
user,
updateUser,
insertBob
}">
<section>
<h1>My User</h1>
<div class="my-user__input">
<label for="firstname">First Name</label>
<input type="text" id="firstname"
:value="user.firstName"
@input="updateUser({ firstName: $event.target.value })" />
</div>
<div class="my-user__input">
<label for="lastname">Last Name</label>
<input type="text" id="lastname"
:value="user.lastName"
@input="updateUser({ lastName: $event.target.value })" />
</div>
<button @click="insertBob()">Insert Bob</button>
</section>
</template>
</my-user-rl>
</section>
</template>
<my-user-rl @input:user="$emit('input:user', $event)">
<template
v-slot:default="{
user,
updateUser,
insertBob
}">
<section>
…
</section>
</template>
</my-user-rl>
BUILDING THE COMPONENT
<template>
<section class="my-user">
<my-user-rl @input:user="$emit('input:user', $event)">
<template
v-slot:default="{
user,
updateUser,
insertBob
}">
<section>
<h1>My User</h1>
<div class="my-user__input">
<label for="firstname">First Name</label>
<input type="text" id="firstname"
:value="user.firstName"
@input="updateUser({ firstName: $event.target.value })" />
</div>
<div class="my-user__input">
<label for="lastname">Last Name</label>
<input type="text" id="lastname"
:value="user.lastName"
@input="updateUser({ lastName: $event.target.value })" />
</div>
<button @click="insertBob()">Insert Bob</button>
</section>
</template>
</my-user-rl>
</section>
</template>
<input type="text" id="lastname"
:value="user.lastName"
@input="updateUser({ lastName: $event.target.value })" />
RENDERLESS RECAP
BUILDING THE COMPONENT
- We’ve got a logic-only component
- Reusable for other ‘views’
- Added a default sample layout
- Based on the same logic layer
📦 Wrap it up and ship it! 📦
WEBPACK TIME, YAY (?)
SHIPPING COMPONENTS
SHIPPING MADE EASY
SHIPPING COMPONENTS
1. SETUP PLUGIN 2. BUILD THE LIBRARY
🎉 ALL DONE 🎉
HEY, WHERE’S THE LINKS?!
ROUNDING UP
GitHub Project:
github.com/larsvanherk/vue-renderless-demo
Adam Wathan’s original post:
adamwathan.me/renderless-components-in-vuejs/
Get in touch:
- @LarsVHerk & @ToThePointIT
🎉 Thank you! 🎉
ToThePoint STS / Lars van Herk / 3 june, 2019

More Related Content

What's hot (20)

PPTX
How to Build SPA with Vue Router 2.0
Takuya Tejima
 
PDF
Virtual Madness @ Etsy
Nishan Subedi
 
PDF
Using Objects to Organize your jQuery Code
Rebecca Murphey
 
PDF
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Ryan Weaver
 
PDF
Best Practices in Plugin Development (WordCamp Seattle)
andrewnacin
 
PDF
Curso Symfony - Clase 4
Javier Eguiluz
 
PDF
Curso Symfony - Clase 2
Javier Eguiluz
 
PDF
Arquitetura de Front-end em Aplicações de Larga Escala
Eduardo Shiota Yasuda
 
ZIP
YUI 3
Dav Glass
 
PDF
GDayX - Advanced Angular.JS
Nicolas Embleton
 
PPTX
AngularJS Animations
Eyal Vardi
 
PPTX
SenchaCon 2016: Want to Use Ext JS Components with Angular 2? Here’s How to I...
Sencha
 
PDF
A New Baseline for Front-End Devs
Rebecca Murphey
 
PDF
DrupalCon jQuery
Nathan Smith
 
PPTX
Academy PRO: React native - navigation
Binary Studio
 
PDF
Dependency Management with RequireJS
Aaronius
 
PDF
Intro To Mvc Development In Php
funkatron
 
PPTX
AngularJS.part1
Andrey Kolodnitsky
 
PDF
Laravel 로 배우는 서버사이드 #5
성일 한
 
How to Build SPA with Vue Router 2.0
Takuya Tejima
 
Virtual Madness @ Etsy
Nishan Subedi
 
Using Objects to Organize your jQuery Code
Rebecca Murphey
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Ryan Weaver
 
Best Practices in Plugin Development (WordCamp Seattle)
andrewnacin
 
Curso Symfony - Clase 4
Javier Eguiluz
 
Curso Symfony - Clase 2
Javier Eguiluz
 
Arquitetura de Front-end em Aplicações de Larga Escala
Eduardo Shiota Yasuda
 
YUI 3
Dav Glass
 
GDayX - Advanced Angular.JS
Nicolas Embleton
 
AngularJS Animations
Eyal Vardi
 
SenchaCon 2016: Want to Use Ext JS Components with Angular 2? Here’s How to I...
Sencha
 
A New Baseline for Front-End Devs
Rebecca Murphey
 
DrupalCon jQuery
Nathan Smith
 
Academy PRO: React native - navigation
Binary Studio
 
Dependency Management with RequireJS
Aaronius
 
Intro To Mvc Development In Php
funkatron
 
AngularJS.part1
Andrey Kolodnitsky
 
Laravel 로 배우는 서버사이드 #5
성일 한
 

Similar to Using Renderless Components in Vue.js during your software development. (20)

PDF
Introduction to Vue.js
Meir Rotstein
 
PDF
Vue fundamentasl with Testing and Vuex
Christoffer Noring
 
PDF
Meet VueJs
Mathieu Breton
 
PPTX
An introduction to Vue.js
TO THE NEW Pvt. Ltd.
 
PPTX
Level up apps and websites with vue.js
Commit University
 
PPTX
Level up apps and websites with vue.js
Violetta Villani
 
PPTX
Don't Over-React - just use Vue!
Raymond Camden
 
ODP
Basics of VueJS
Squash Apps Pvt Ltd
 
PDF
Advantages of Vue JS - Presented at the Rangle.io VueJS Meetup in January
Evan Schultz
 
PDF
Vue.js for beginners
Julio Bitencourt
 
PDF
Learning Vue Directives.pdf
murad khan
 
PDF
Intro to VueJS Workshop
Rafael Casuso Romate
 
PDF
Creating 'Vuetiful' Data-Driven User Interfaces
Evan Schultz
 
PDF
VueJS: The Simple Revolution
Rafael Casuso Romate
 
PDF
Vue.js 101
Mark Freedman
 
PDF
Introduction to VueJS & Vuex
Bernd Alter
 
PDF
ITB2019 ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 V...
Ortus Solutions, Corp
 
PDF
Love at first Vue
Dalibor Gogic
 
ODP
An Introduction to Vuejs
Paddy Lock
 
PDF
Vue js 2.x
Suresh Velusamy
 
Introduction to Vue.js
Meir Rotstein
 
Vue fundamentasl with Testing and Vuex
Christoffer Noring
 
Meet VueJs
Mathieu Breton
 
An introduction to Vue.js
TO THE NEW Pvt. Ltd.
 
Level up apps and websites with vue.js
Commit University
 
Level up apps and websites with vue.js
Violetta Villani
 
Don't Over-React - just use Vue!
Raymond Camden
 
Basics of VueJS
Squash Apps Pvt Ltd
 
Advantages of Vue JS - Presented at the Rangle.io VueJS Meetup in January
Evan Schultz
 
Vue.js for beginners
Julio Bitencourt
 
Learning Vue Directives.pdf
murad khan
 
Intro to VueJS Workshop
Rafael Casuso Romate
 
Creating 'Vuetiful' Data-Driven User Interfaces
Evan Schultz
 
VueJS: The Simple Revolution
Rafael Casuso Romate
 
Vue.js 101
Mark Freedman
 
Introduction to VueJS & Vuex
Bernd Alter
 
ITB2019 ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 V...
Ortus Solutions, Corp
 
Love at first Vue
Dalibor Gogic
 
An Introduction to Vuejs
Paddy Lock
 
Vue js 2.x
Suresh Velusamy
 
Ad

Recently uploaded (20)

PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
PPTX
Change Common Properties in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PDF
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
PDF
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PDF
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
PPTX
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
PPTX
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
PDF
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PDF
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PDF
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
PDF
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PPTX
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
Change Common Properties in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
In From the Cold: Open Source as Part of Mainstream Software Asset Management
Shane Coughlan
 
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Ad

Using Renderless Components in Vue.js during your software development.

  • 1. Vue.js Renderless Components It’s like advanced internet Legos! ToThePoint STS / Lars van Herk / 3 june, 2019
  • 2. 1. Build a standard, feature-rich base component 2. Separate the view from the logic 3. Slap it into a publishable library WHAT’CHA GONNA DO? INTRODUCTION We’re gonna do some Vue.
  • 3. WHY SO COMPLICATED? INTRODUCTION Every app works differently - “Our date pickers don’t look like that!” - Tweaking a prebuilt component’s layout is hard or impossible - Either accept it, or rebuild it
  • 4. WHAT DO WE NEED FOR THIS? INTRODUCTION Slots. Scoped Slots. https://vuejs.org/v2/guide/components-slots.html
  • 5. <template> <section class="my-alert"> <slot name="title"> <h1>This will be the default title!</h1> </slot> <slot v-bind:person="person"> Hello, {{ person.name }}! </slot> </section> </template> <template> <div id="app"> <my-alert :person="outerPerson"> <template v-slot:title> <h1>I'm going to replace the default!</h1> </template> </my-alert> </div> </template> <template> <section class="my-alert"> <h1>I'm going to replace the default!</h1> Hello, Bobby! </section> </template> MyAlert.vue App.vue Rendered Output INTRODUCTION
  • 6. RENDERING ALL THE THINGS! INTRODUCTION - Template part of SFC isn’t required! - Can be replaced with a render function - Also known as the ‘h(…)’ function - ‘render()’: available in ‘script’ section
  • 7. THE STARTING BLOCKS BUILDING THE COMPONENT 1. Build the basic component 2. Split logic from rendering 3. Use our old view as a default BRACE YOURSELVES, CODE AHOY!
  • 8. BUILDING THE COMPONENT <script> export default { data: () => ({ user: { firstName: '', lastName: '' } }), watch: { user: { handler (val) { this.$emit('input:user', val); }, deep: true } }, methods: { insertBob () { this.user = { firstName: 'Bob', lastName: 'Marley' }; } } }; </script> <template> <section class="my-user"> <h1>My User</h1> <div class="my-user__input"> <label for="firstname">First Name</label> <input type="text" id="firstname" v-model="user.firstName"> </div> <div class="my-user__input"> <label for="lastname">Last Name</label> <input type="text" id="lastname" v-model="user.lastName"> </div> <button @click="insertBob()">Insert Bob</button> </section> </template>
  • 9. BUILDING THE COMPONENT <script> export default { data: () => ({ scopeData: { user: { firstName: '', lastName: '' } } }), watch: { 'scopeData.user': { … } }, methods: { updateUser (data) { … }, insertBob () { … } }, render () { return this.$scopedSlots.default({ // TODO }); } }; </script> <script> export default { data: () => ({ user: { firstName: '', lastName: '' } }), watch: { user: { handler (val) { this.$emit('input:user', val); }, deep: true } }, methods: { insertBob () { this.user = { firstName: 'Bob', lastName: 'Marley' }; } } }; </script>
  • 10. BUILDING THE COMPONENT <script> export default { data: () => ({ scopeData: { user: { firstName: '', lastName: '' } } }), … render () { return this.$scopedSlots.default({ // DATA ...this.scopeData, // ACTIONS updateUser: this.updateUser, insertBob: this.insertBob }); } }; </script>
  • 11. WE’RE ALMOST THERE 🎉 BUILDING THE COMPONENT 1. Build the basic component 2. Split logic from rendering 3. Use our old view as a default
  • 12. BUILDING THE COMPONENT <template> <section class="my-user"> <h1>My User</h1> <div class="my-user__input"> <label for="firstname">First Name</label> <input type="text" id="firstname" v-model="user.firstName"> </div> <div class="my-user__input"> <label for="lastname">Last Name</label> <input type="text" id="lastname" v-model="user.lastName"> </div> <button @click="insertBob()">Insert Bob</button> </section> </template> <template> <section class="my-user"> <my-user-rl @input:user="$emit('input:user', $event)"> <template v-slot:default="{ user, updateUser, insertBob }"> <section> <h1>My User</h1> <div class="my-user__input"> <label for="firstname">First Name</label> <input type="text" id="firstname" :value="user.firstName" @input="updateUser({ firstName: $event.target.value })" /> </div> <div class="my-user__input"> <label for="lastname">Last Name</label> <input type="text" id="lastname" :value="user.lastName" @input="updateUser({ lastName: $event.target.value })" /> </div> <button @click="insertBob()">Insert Bob</button> </section> </template> </my-user-rl> </section> </template>
  • 13. BUILDING THE COMPONENT <template> <section class="my-user"> <my-user-rl @input:user="$emit('input:user', $event)"> <template v-slot:default="{ user, updateUser, insertBob }"> <section> <h1>My User</h1> <div class="my-user__input"> <label for="firstname">First Name</label> <input type="text" id="firstname" :value="user.firstName" @input="updateUser({ firstName: $event.target.value })" /> </div> <div class="my-user__input"> <label for="lastname">Last Name</label> <input type="text" id="lastname" :value="user.lastName" @input="updateUser({ lastName: $event.target.value })" /> </div> <button @click="insertBob()">Insert Bob</button> </section> </template> </my-user-rl> </section> </template> <my-user-rl @input:user="$emit('input:user', $event)"> <template v-slot:default="{ user, updateUser, insertBob }"> <section> … </section> </template> </my-user-rl>
  • 14. BUILDING THE COMPONENT <template> <section class="my-user"> <my-user-rl @input:user="$emit('input:user', $event)"> <template v-slot:default="{ user, updateUser, insertBob }"> <section> <h1>My User</h1> <div class="my-user__input"> <label for="firstname">First Name</label> <input type="text" id="firstname" :value="user.firstName" @input="updateUser({ firstName: $event.target.value })" /> </div> <div class="my-user__input"> <label for="lastname">Last Name</label> <input type="text" id="lastname" :value="user.lastName" @input="updateUser({ lastName: $event.target.value })" /> </div> <button @click="insertBob()">Insert Bob</button> </section> </template> </my-user-rl> </section> </template> <input type="text" id="lastname" :value="user.lastName" @input="updateUser({ lastName: $event.target.value })" />
  • 15. RENDERLESS RECAP BUILDING THE COMPONENT - We’ve got a logic-only component - Reusable for other ‘views’ - Added a default sample layout - Based on the same logic layer 📦 Wrap it up and ship it! 📦
  • 16. WEBPACK TIME, YAY (?) SHIPPING COMPONENTS
  • 17. SHIPPING MADE EASY SHIPPING COMPONENTS 1. SETUP PLUGIN 2. BUILD THE LIBRARY 🎉 ALL DONE 🎉
  • 18. HEY, WHERE’S THE LINKS?! ROUNDING UP GitHub Project: github.com/larsvanherk/vue-renderless-demo Adam Wathan’s original post: adamwathan.me/renderless-components-in-vuejs/ Get in touch: - @LarsVHerk & @ToThePointIT
  • 19. 🎉 Thank you! 🎉 ToThePoint STS / Lars van Herk / 3 june, 2019