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

    🔥 (#200) Default content, debugging templates, and more

    We made it to 200!

    Thanks for reading and supporting me over the last few years, it means a lot to me.

    Tomorrow is the last day of the Composable Design Patterns course launch and the 35% off discount. If you were hoping to pick it up, don't forget to check it out!

    As always, I've got some tips and links for you, and a new podcast episode.

    Enjoy, and have a great week!

    — Michael

    🔥 Default Content with Slots

    You can provide fallback content for a slot, in case no content is provided:

    <!-- Child.vue -->
    <template>
    <div>
    <slot>
    Hey! You forgot to put something in the slot!
    </slot>
    </div>
    </template>

    This content can be anything, even a whole complex component that provides default behaviour:

    <!-- Child.vue -->
    <template>
    <div>
    <slot name="search">
    <!-- Can be overridden with more advanced functionality -->
    <BasicSearchFunctionality />
    </slot>
    </div>
    </template>

    🔥 Debugging Templates

    If you ever need to debug what’s happening inside of a template, you can just throw in a function:

    <template>
    <div v-for="i in 4" :key="i">
    {{ log(i) }}
    {{ i + 1 }}
    </div>
    </template>

    Vue will execute anything within the curly braces as Javascript, so this function is called normally.

    It can be whatever you want. Set it to console.log if you just want to log out some values:

    const log = console.log;

    Or add in a debugger statement so you can step through the code one line at a time and inspect the variables more closely:

    const log = (val) => {
    debugger;
    };

    If we want global access to a debugging utility, we can use the globalProperties field on our app config:

    app.config.globalProperties.$log = console.log;

    Now, we can use this $log method in whatever component we want:

    🔥 Reactive CSS

    In Vue 3 we can use reactive values in our <style> block just like we can in the <template> block:

    <style scoped>
    .button {
    color: v-bind(buttonColor);
    }
    </style>

    Behind the scenes, Vue uses CSS computed properties (aka CSS variables) scoped to each component.

    The CSS remains static, but we can dynamically update the CSS variables whenever the reactive value changes.

    More info can be found in the docs.

    🔥 List Component Pattern

    Large lists in components can lead to cluttered and unwieldy templates. The solution is to abstract the v-for loop logic into a child component.

    This simplifies the parent and encapsulates the iteration logic in a dedicated list component, keeping things nice and tidy.

    <!-- Before: Direct v-for in the parent component -->
    <template>
    <div v-for="item in list" :key="item.id">
    <!-- Lots of code specific to each item -->
    </div>
    </template>
    <!-- After: Abstracting v-for into a child component -->
    <template>
    <NewComponentList :list="list" />
    </template>

    To learn more about this pattern and 20 more, check out Clean Components Toolkit.

    🎙️ #042 — Creating Technical Content (with Adam Jahr)

    In this episode, Michael talks with Adam Jahr, Founder of Vue Mastery, all about creating technical content - and how this is relevant for you as a developer.

    Tune in and figure out how Adam founded Vue Mastery, what his biggest learnings from his Coding Bootcamp times were and learn key tips that can set your content apart from others!

    And as a bonus - learn what creating content, regardless the format, has to do with Harry Potter or Lord of the Rings.

    Watch on YouTube.

    Chapters:

    In case you missed them:

    đź“ś Adding Drag and Drop (video)

    In this video from LearnVue, we see how easy it can be to add a powerful drag and drop system in to your app.

    Check it out here: Adding Drag and Drop (video)

    đź“ś Nuxt State Management: Pinia vs useState

    In Nuxt we get a new useState composable.

    But how does it compare to Pinia?

    In this article for Vue Mastery, I discuss the main differences and when to use each.

    Check it out here: Nuxt State Management: Pinia vs useState

    đź“… Upcoming Events

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

    Vuejs Amsterdam 2025 — (March 12, 2025 to March 13, 2025)

    The biggest Vue conference in the world! A two-day event with workshops, speakers from around the world, and socializing.

    Check it out here

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

    A great Vue conference, this year held in Tampa. Two days of conference talks, plus a day for workshops.

    Check it out here

    đź’¬ Chaos

    "Automating chaos just gives faster chaos." — Mark Fewster

    🧠 Spaced-repetition: Inline Composables

    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.

    You can define composables inline, keeping them in your SFC file:

    <script setup>
    const useCount = (i) => {
    const count = ref(0);
    const increment = () => count.value += 1;
    const decrement = () => count.value -= 1;
    return {
    id: i,
    count,
    increment,
    decrement,
    };
    };
    const listOfCounters = [];
    for (const i = 0; i < 10; i++) {
    listOfCounters.push(useCount(i));
    }
    </script>
    <template>
    <div v-for="counter in listOfCounters" :key="counter.id">
    <button @click="counter.decrement()">-</button>
    {{ counter.count }}
    <button @click="counter.increment()">+</button>
    </div>
    </template>

    But is there any point to doing this?

    If you’re keeping your components focused on a specific task (and you should be), then it stands to reason that the logic is also focused on a single task.

    This means that if you wrap up all relevant logic into an inline composable, you’ve wrapped up all — or nearly all — the logic that this component has:

    <script setup>
    // Create an inline composable
    const useStuff = () => {
    <all_our_logic>
    };
    // ...only to destructure most of it to use in our template
    const {
    value,
    anotherValue,
    eventHandler,
    anotherEventHandler
    } = useStuff();
    </script>

    At which point, we might as well write our logic without that unnecessary wrapper:

    <script setup>
    const value = ...
    const anotherValue = ...
    const eventHandler = ...
    const anotherEventHandler = ...
    </script>

    However, if you have do have logic that can be encapsulated nicely within this inline composable, it could make your code cleaner and easier to use.

    Using lexical scoping to create more boundaries within your files helps you to understand and think through your code, which is always helpful.

    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.