Vue Slots and Reusable components
crisarji
Posted on May 8, 2021
Vue Slots and Reusable components
Hello developer pal!, glad to see you here.
In this post, we will take a look at the way a simple feature as it is slot
in vue could spare a lot of time and effort when having the same components displaying different data.
Sometimes, we need to replicate the same task with different data, for instance, you have a design system which determines that every single list element throughout the site needs to be consistent, this means having the same height, width, font, etc. Sounds fair!
For accomplishing this, there are 2 options:
Copy + Paste
the same listing component in multiple places; the fallback of this approach comes when, for example, the font of the list item needs to be updated; if you, by chance, have in the project 1, 2 or 3 list items, you can manually make the change, all good!, but what happens when your project has a whole bunch of listing components?, it would be required go one by one and make the change; the effort on dev, qa, and the risk of letting one scenario out of the scope is high.Create a
Reusable Component
, this will allow it to make the change in one only place and affect all of them at once!, here theslot
concept comes handy, when using aslot
, you can have the same look and feel, behavior, properties and others available for all the listing components.
Show Me The Code
The steps to be focused on are:
- Having 1 reusable listing component
- Having different view components, injected with different data
- Having different view components, displaying different elements
Let me share to you the GitHub code here.
1. Having 1 reusable listing component
How would it look a slot
for the example purposes?:
<template>
<div>
<ul>
<li v-for="(element, index) in elements" :key="element.id">
<slot name="element" v-bind:element="element" v-bind:index="index"></slot>
</li>
</ul>
</div>
</template>
In the snippet above, there is a v-for
directive which loops over the array in a property named elements
; what it is happening is that every single element, and its index, are available to be part of the template, the slot
has the option for binding values, these are available as soon as the slot
is invoked.
This simple is to have a reusable component with slots
!, the html elements can be modified as required: add css, new attributes, new binding props, everything will be ready to be used when invoked the component(check the GitHub repo for a nicer experience including Tailwind
).
2. Having different view components, injected with different data
For the sake of the exercise, 3 different arrays are present for feeding the view components:
export const agents = [
{ id: '07531267-D', name: 'Remedios Carmona', calls: 12, deals: 5 },
{ id: '91958619', name: 'Dalal Heidema', calls: 20, deals: 12 },
{ id: 'NNaN31539321', name: 'Julien Legrand', calls: 25, deals: 17 },
{ id: '1NNaN60472038', name: 'Karina da Cunha', calls: 33, deals: 25 },
{ id: '060469-1435', name: 'Evelyn Scheerer', calls: 40, deals: 35 },
];
export const supervisors = [
{ id: '75687', name: 'Idelso Gonçalves', agents: 10, teams: 1, gender: 'male' },
{ id: '2NNaN64983816', name: 'Cassandra Leroy', agents: 20, teams: 2, gender: 'female' },
{ id: 'N901057Z', name: 'Arron Johnston', agents: 30, teams: 3, gender: 'male' },
{ id: '18066349671', name: 'Siham Reitan', agents: 40, teams: 4, gender: 'female' },
{ id: '48926083', name: 'Mariam Linde', agents: 50, teams: 5, gender: 'female' },
];
export const managers = [
{ id: 'NaNNA831undefined', name: 'Niilo Keranen', department: 'IT', gender: 'male' },
{ id: '2NNaN40789264', name: 'Leana Deschamps', department: 'Operations', gender: 'female' },
{ id: '283707860', name: 'Irma Boyd', department: 'HHRR', gender: 'female' },
{ id: '290471', name: 'Nicole Oehme', department: 'ACC', gender: 'female' },
{ id: '1NNaN44873525', name: 'Antonin Rey', department: 'Facilities', gender: 'male' },
];
As you can notice, the views
will be Agents
, Supervisors
and Managers
; as aforementioned, this items must be listed up following a design system specifications(width, height, font, typo) for keeping the consistency.
Let's suppose that the design system ask for something like these:
Agents
view:
Supervisors
view:
Managers
view:
After taking a look at the mocking data and the requirements, what is changing are the fields to display, the order, and the background, since the Copy+Paste
approach is discarded, the other possible way to go is the Reusable Components.
3. Having different view components, displaying different elements
Let's dig a bit into the implementation of the Reusable Component and slots.
The very first view is the one for Agents
, we need to import the reusable component, register it, add an input property for feeding the list of elements and render it out(skipped steps in here, you can check the source code for more info), let focus in the template
Agents
view:
<template>
<custom-list :listElements="listElements" itemStyling="justify-between bg-gray-300">
<template v-slot:element="{ element }">
<div class="flex w-1/5"></div>
<div class="flex w-2/5"></div>
<div class="flex w-2/5"></div>
</template>
</custom-list>
</template>
A couple of interesting things from above snippet:
-
custom-list
(our reusable component) is expecting for the list of elements and an item styling, also, it is accessing theelement
binding, so the data to be display is dynamic.
What about the second view?
Supervisors
view:
<template>
<custom-list :listElements="listElements" itemStyling="justify-between bg-blue-300">
<template v-slot:element="{ element }">
<div class="flex w-2/5"></div>
<div class="flex w-1/5"></div>
<div class="flex justify-end w-2/5"></div>
</template>
</custom-list>
</template>
This is pretty similar to the previous one, the biggest difference is that a different color is send to affect the background(in case you are not familiar with Tailwind, it is this bg-blue-300
), and the order of the divs(the avatar from the mocks will be placed at the center)
Last but not least:
Managers
view:
<template>
<custom-list :listElements="listElements" itemStyling="justify-between bg-green-300">
<template v-slot:element="{ element, index }">
<div class="flex w-2/5"></div>
<div class="flex justify-center w-2/5"></div>
<div class="flex w-1/5"></div>
</template>
</custom-list>
</template>
Also similar to the other 2(that's the idea), but changing the background color again, the order of the elements to be displayed(avatar at the end) and also including the other binding property declared in the reusable component, the index
.
After all the steps above, this is the output:
Notes:
- You can find the repo for Vue2 and Vue3
- Feel free to fork it and/or import it in an online code editor(I tried but there seems to be a known error )
Challenge: The CustomList
component could be register globally, in case you want to stop importing it throughout the site
Conclusion
As shown above, the slots
could spare some precious development time, help with the scalability and be customized as required; maybe you could have a better way to do it, let's discuss in a thread below!
Thanks for reading!
Posted on May 8, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.