Join 13,567+ other Vue devs and get exclusive tips and insights delivered straight to your inbox, every week.
👋Hey friend! I work hard to send you amazing stuff each week.
— Michael
Hey!
This week you can get the Vue Tips Collection hardcover for only $47.
That includes free shipping to the US, Canada, and the EU. It’s 220 pages, full color, with 118 tips across 7 themed chapters. Syntax, reactivity, patterns, everything you could want.
Of course, I've always got tips for you (and more!) in this email.
Have a great week!
— Michael
I decided to see if I could make a v-for
component using only the template. Along the way, I discovered how to use slots recursively, too.
This is what the component looks like:
<!-- VFor.vue --><template><div><!-- Render the first item -->{{ list[0] }}<!-- If we have more items, continue!But leave off the item we just rendered --><v-forv-if="list.length > 1":list="list.slice(1)"/></div></template>
If you wanted to do this with scoped slots — and why wouldn't you?! — it just takes a few tweaks:
<template><div><!-- Pass the item into the slot to be rendered --><slot v-bind:item="list[0]"><!-- Default -->{{ list[0] }}</slot><v-forv-if="list.length > 1":list="list.slice(1)"><!-- Recursively pass down scoped slot --><template v-slot="{ item }"><slot v-bind:item="item" /></template></v-for></div></template>
Here is how this component is used:
<template><div><!-- Regular list --><v-for :list="list" /><!-- List with bolded items --><v-for :list="list"><template v-slot="{ item }"><strong>{{ item }}</strong></template></v-for></div></template>
For a more detailed explanation of this example and nested slots, check out my blog post on it:
How to Use Nested Slots in Vue (including scoped slots)
Here's a technique that makes it super easy to simplify nested elements:
You take everything inside a v-if
or v-for
and extract it into a new component.
You'll go from this, with some nesting:
<template><div><!-- ... --><div v-for="item in list"><h2 class="item-title">{{ item.title }}</h2><p class="item-description">{{ item.description }}</p></div><!-- ... --></div></template>
To this, where the nesting is gone:
<template><div><!-- ... --><ListItemv-for="item in list":item="item"/><!-- ... --></div></template>
To do this, you extract the code in the v-for
into a new component:
<!-- ListItem.vue --><template><div><h2 class="item-title">{{ item.title }}</h2><p class="item-description">{{ item.description }}</p></div></template>
This technique becomes more and more valuable the more nesting you have.
Note: You can choose to do this recursively, taking every v-for
or v-if
and creating a new component. But often, it's simpler to grab a more significant chunk of the template and remove most of the nesting with one new component.
I share more about this in my course, Clean Component Toolkit.
An extremely common question I get asked all the time is, “how do you know when to split up a component?”
I want to share a simple pattern with you that is basically fool-proof, and can be applied to lots of components with almost no thought.
When we encounter a v-if
(or v-show
) in our template, there's one main pattern we can use:
Extracting the body of each branch into its own component.
This is just one of many patterns included in Clean Components. There, we go into much more detail, examining each pattern more closely and really fine-tuning our understanding.
When we extract each branch body we go from this:
<div v-if="condition"><div><!-- Lots of code here --></div></div><div v-else><div><!-- Lots of other code --></div></div>
To this:
<div v-if="condition"><NewComponent /></div><div v-else><OtherComponent /></div>
We know we can do this for two reasons:
We know that each branch is semantically related, meaning all of that code works together to perform the same task.
Each branch also does distinct work — otherwise, why have a v-if
at all?
This means it's a perfect opportunity to create new components.
And by replacing a large chunk of code with a well-named component that represents the code’s intent, we make our code much more self-documenting. But we’ll get to that later on.
In this episode of DejaVue, Alex sits down with James Garbutt, open source maintainer and lead of the e18e initiative. James shares his journey from writing web scrapers as a teenager to maintaining critical JavaScript libraries like parse5 or Chokidar and eventually co-creating the ecosystem performance initiative.
The conversation is then all around e18e, which aims to improve performance across the JavaScript ecosystem through three pillars:
James explains how the community-driven approach has produced impressive results all across the web development landscape.
Learn about real-world examples of performance improvements, including replacement packages like tinyglobby and nano-staged, and discover how to contribute to e18e even if you're new to open source. James shares also insights on balancing between backward compatibility and performance, bundling dependencies, and also shares future plans for e18e in 2025.
Watch on YouTube or listen on your favorite podcast platform.
Chapters:
In case you missed them:
Nuxt gives us two great options for managing all of our assets in our web app.
But what’s the difference, and how do you know which to use?
In this article I’ll share some simple questions you can ask yourself to figure out where to put your assets, as well as the differences between the two strategies.
Check it out here: Handling Assets in Nuxt
Trying to manage database schemas alongside your Nuxt app types can be a challenge.
But with Prisma, most of these problems go away.
It handles all of the boilerplate and coordination, so you just write one single schema that’s used in your database and in your TypeScript app.
In this article I show you how to create your Prisma schema.
Check it out here: Prisma with Nuxt: Creating the Prisma Schema (2 of 5)
Here are some upcoming events you might be interested in. Let me know if I've missed any!
VueConf US 2025 is a great Vue conference, this year held in Tampa from May 13–15, with two days of talks and a day of workshops. Unfortunately, I am no longer able to make it to the conference this year. I hope everyone attending has an amazing time and I look forward to joining in the future!
It's time to get together in Madrid. Join for a full day of talks, activities, and networking with the Vue.js community and ecosystem.
"There are only two industries that refer to their customers as 'users'." — Edward Tufte
The best way to commit something to long-term memory is to periodically review it, gradually increasing the time between reviews 👨🔬
Actually remembering these tips is much more useful than just a quick distraction, so here's a tip from a couple weeks ago to jog your memory.
Context-aware components are "magical" — they adapt to what's going on around them automatically, handling edge cases, state sharing, and more.
There are 3 main types of context-aware components, but configuration is the one I find most interesting.
When you break up a large component into smaller ones, they often still need to share state.
Instead of pushing that work on whoever's consuming the components, you can make this happen "behind the scenes."
To give you more flexibility, you may break up a Dropdown
component into Select
and Option
components. But to make it easier to use, the Select
and Option
components share the selected
state with each other:
<!-- Used as a single component for simplicity --><Dropdown v-model="selected" :options="[]" /><!-- Split up for more flexibility --><Select v-model="selected"><Option value="mustard">Mustard</Option><Option value="ketchup">Ketchup</Option><div class="relish-wrapper"><Option value="relish">Relish</Option></div></Select>
Sometimes component behaviour needs to change based on what's going on in the rest of the application. This is often done to automagically handle edge cases that would otherwise be annoying to deal with.
A Popup
or Tooltip
should reposition itself so it doesn't overflow out of the page. But if that component is inside a modal, it should move, so it doesn't overflow out of the modal.
This can be done automagically if the Tooltip
knows when it's inside a modal.
You already create context-aware CSS, applying different styles based on what's happening in parent or sibling elements.
.statistic {color: black;font-size: 24px;font-weight: bold;}/* Give some separation between statsthat are right beside each other */.statistic + .statistic {margin-left: 10px;}
CSS variables let us push this further, allowing us to set different values in different parts of the page.
Michael Hoffman curates a fantastic weekly newsletter with the best Vue and Nuxt links.
p.s. I also have a bunch of products/courses: