Exclusive tips every week

Join 13,567+ other Vue devs and get exclusive tips and insights delivered straight to your inbox, every week.

    Picture of Michael Thiessen

    👋Hey friend! I work hard to send you amazing stuff each week.

    — Michael

    I really love and enjoy reading these emails.

    You are one of the most pro VueJS devs I know, and I am happy that you share this knowledge.

    Fabian Beer

    Here's my latest newsletter

    🔥 (#213) Recursive slots, lonely children, and extracting conditional patterns

    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.

    Go here to grab your copy.

    Of course, I've always got tips for you (and more!) in this email.

    Have a great week!

    — Michael

    🔥 Recursive slots

    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-for
    v-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-for
    v-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)

    🔥 Lonely children

    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>
    <!-- ... -->
    <ListItem
    v-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.

    🔥 Extract Conditional Pattern

    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:

    1. Each branch is semantically related
    2. Each branch does distinct work

    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.

    🎙️ #055 — e18e: Ecosystem Performance (with James Garbutt)

    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:

    • Cleaning up dependency trees
    • Speeding up popular packages
    • Creating lighter alternatives to bloated libraries

    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:

    📜 Handling Assets in Nuxt

    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

    📜 Prisma with Nuxt: Creating the Prisma Schema (2 of 5)

    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)

    📅 Upcoming Events

    Here are some upcoming events you might be interested in. Let me know if I've missed any!

    VueConf US 2025 — (May 13, 2025 to May 15, 2025)

    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!

    Check it out here

    MadVue 2025 — (May 29, 2025)

    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.

    Check it out here

    💬 "Users"

    "There are only two industries that refer to their customers as 'users'." — Edward Tufte

    🧠 Spaced-repetition: Creating Magic with Context-Aware Components

    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.

    1. State Sharing

    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>

    2. Configuration

    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.

    3. Styling

    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 stats
    that 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.

    Sign up for it here.

    p.s. I also have a bunch of products/courses:

    Here's what others are saying

    I'm starting to think that your newsletter is one of the best things that happened to me this year. I just love these emails.
    Stanislaw Gregor
    I'm somewhere in the upper-middle level at Vue, and I never miss an email you and always find something cool when reading!
    Eduard Climov
    This is the first time where I'm actually enjoying email newsletters. I like your format a lot.
    Fahmi Alfituri
    You have great content in your emails. I seriously learn something from every one of them.
    Titus Decali
    Just wanted to say I enjoy these emails. They encourage me to constantly improve my craft. Fantastic work.
    Joe Radman
    Thanks for another beautiful tip 🙏
    Victor Martins Onuoha
    Loving these, and the spaced repetition.
    Mark Goldstein
    I really enjoy reading your emails, because I love Vue. Thanks for these emails.
    Arturo Espinoza
    I really love and enjoy reading these emails. You are one of the most pro VueJS devs I know, and I am happy that you share this knowledge.
    Fabian Beer
    THANK YOU! I did not know about the deep property, so I assumed you simply couldn't watch objects.
    Darryl Noakes
    I really must say you are doing a really great job. Now I am aware of a cleaner and more performant way to use Tailwind. Thanks a lot!
    Henry Eze
    Thank you so much, I really enjoy and appreciate your emails.
    Carlos Gonzalez
    Thanks for sharing great Vue tips.
    Fernando Navarro
    I really enjoy these tips.
    Martin H
    Thank you so much for the weekly Vue education. Thanks and live on longer to educate us more.
    Kabolobari Benakole
    I look forward to your emails every week. This week was something I knew, but I like to be reminded of. Thanks for keeping it up!
    Nathan Strutz
    Thank you for your weekly emails. I always look forward to learning a new tip about Vue or at least relearning old tips :)
    Colin Johnson
    I have really been enjoying your weekly emails, and I also got my two team members to join in on the fun as well.
    Keith Dawson
    Thank you for your newsletter, your explanations have very concise examples and I like it.
    Nicolas Decayeux
    Thanks A LOT for your great work!!! One of the few newsletters that I let pass!
    Martin Tillmann

    Want to level up your Vue skills?

    With over two million reads and 11,067 subscribers, you've come to the right place.

    Subscribe now to get exclusive insights and tips every week.