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

    🔥 (243) Nuxt Image v2, Nuxt 4.2, and more

    Hey everyone,

    Last week, Nuxt Image v2 was released. The main story here is much better TypeScript support, but of course, there are lots of other improvements! You can read the announcement here.

    And if you missed it, Nuxt 4.2 was also released just a few weeks ago. That announcement is here.

    Have a great week!

    — Michael

    🔥 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.

    🔥 Component Metadata

    Not every bit of info you add to a component is state. For example, sometimes, you need to add metadata that gives other components more information.

    For example, if you're building a bunch of different widgets for an analytics dashboard like Google Analytics or Stripe.

    If you want the layout to know how many columns each widget should take up, you can add that directly on the component as metadata:

    <script setup>
    defineOptions({
    columns: 3,
    });
    </script>

    Or if you're using the Options API:

    export default {
    name: 'LiveUsersWidget',
    // Just add it as an extra property
    columns: 3,
    props: {
    // ...
    },
    data() {
    return {
    //...
    };
    },
    };

    You'll find this metadata as a property on the component:

    import LiveUsersWidget from './LiveUsersWidget.vue';
    const { columns } = LiveUsersWidget;

    With the Composition API we can't access this value directly, because there's no concept of a "current instance". Instead, we can make our value a constant:

    <script setup>
    const columns = 3;
    defineOptions({
    columns,
    });
    </script>

    But this value cannot change, because defineOptions is a compiler macro and the value is used at compile time.

    If you're using the Options API you can access the metadata from within the component through the special $options property:

    export default {
    name: 'LiveUsersWidget',
    columns: 3,
    created() {
    // `$options` contains all the metadata for a component
    console.log(`Using ${this.$options.columns} columns`);
    },
    };

    Just keep in mind that this metadata is the same for each component instance and is not reactive.

    Other uses for this include (but are not limited to):

    • Keeping version numbers for individual components
    • Custom flags for build tools to treat components differently
    • Adding custom features to components beyond computed props, data, watchers, etc.
    • and many more I can't think of!

    I used this technique to build my Totally Unnecessary If/Else Component if you want to see it in action.

    🔥 Start with the Interface

    When writing a composable, don’t immediately dive into implementing it.

    Instead, take a moment to figure out how you will be using the component. Take some time to think about the interface between the composable and the rest of your app.

    A few minutes upfront can save you a lot of tears and frustration later on.

    Here are a few questions you may want to ask yourself before starting:

    1. What arguments should the composable receive?
    2. What options do we want to include?
    3. What does the composable return?
    4. Do we want to use dynamic return values here?
    5. What does the minimum useful version look like, and how quickly can we get there?
    6. What does the final version look like? Is there anything easy we can do now to prepare for that?

    Of course, your composable will change and evolve over time.

    But it’s much easier to start off heading in the right direction.

    📜 Mastering Prose Components in Nuxt Content

    Prose components are perhaps one of the best features of Nuxt Content!

    In this article, we'll go through a few examples of how you can easily create your own.

    Check it out here: Mastering Prose Components in Nuxt Content

    The NuxtLink component may seem simple at first glance, but there’s a lot going on beneath the surface.

    It’s one of the easiest Nuxt components to use, while giving our apps a big performance boost.

    In this article we see some things about NuxtLink you may not have known.

    Check it out here: Better Navigation with NuxtLink

    đź’¬ Frustation

    "Give someone a program, you frustrate them for a day; teach them how to program, you frustrate them for a lifetime." — David Leinweber

    đź§  Spaced-repetition: Hybrid API: Composition API + Options API

    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 don’t have to decide between Options API and Composition API, you can use both:

    export default {
    setup() {
    const darkMode = ref(false);
    return { darkMode }
    },
    methods: {
    saveDarkMode() {
    localStorage.setItem('dark-mode', this.darkMode);
    },
    }
    };

    We can also update values from the Options API:

    export default {
    setup() {
    const darkMode = ref(false);
    return { darkMode }
    },
    methods: {
    changeTheme(val) {
    this.darkMode = val;
    }
    }
    };

    Although you can access Composition API from the Options API, it’s a one-way street. The Composition API cannot access anything defined through the Options API:

    export default {
    setup() {
    const darkMode = ref(false);
    // We can't access the method
    this.changeTheme(true);
    return { darkMode }
    },
    methods: {
    changeTheme(val) {
    this.darkMode = val;
    }
    }

    This can be useful for incremental adoption of the Composition API, because it lets you use reusable composables in your Options API.

    But mixing two styles of writing components is likely to cause more headaches than it solves, so please think twice before doing this!

    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.