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

    🔥 (233) Writable Computed Refs, Hidden Components, and Render Functions

    Hi!

    This week is a bit quieter for me. I just wrapped up the launch of Advanced Reactivity, so I'm switching gears a little.

    So, no new articles for you this week, but I've got some from the archives that you might have missed!

    And of course, your tips, as always.

    Have a fantastic week!

    — Michael

    🔥 Writable Computed Refs

    Computed refs are cool and all, but did you know you can create writable computed refs?

    const firstName = ref('');
    const lastName = ref('');
    const fullName = computed({
    get: () => `${firstName.value} ${lastName.value}`,
    set: (val) => {
    const split = val.split(' '); // ['Michael', 'Thiessen']
    firstName.value = split[0]; // 'Michael'
    lastName.value = split[1]; // 'Thiessen'
    }
    });
    fullName.value = 'Michael Thiessen';
    console.log(lastName.value); // 'Thiessen'

    If you want to learn more about writable computed refs (and other advanced reactivity patterns), check out my course Advanced Reactivity.

    🔥 When to use the Hidden Component Pattern

    It’s just as important to know when not to use a pattern as it is to know how to use a pattern.

    For Hidden Components, it comes down to whether we’re dealing with dynamic, reactive values, or values that are hard-coded.

    Following this pattern we factor out the collapse prop. We end up with two components, for when collapse is true and for when it's false:

    <!-- `collapse` is true -->
    <ArticlesCollapsed />
    <!-- `collapse` is true -->
    <ArticlesExpanded />

    But if we always use these components where we're dynamically switching between them, we now have to use an extra wrapper component:

    <!-- Articles.vue -->
    <template>
    <ArticlesCollapsed v-if="collapse" />
    <ArticlesExpanded v-else />
    </template>

    Our code is easier to understand, but we haven't necessarily simplified our code.

    In a way, we’re back to where we started, switching between behaviours based on the collapse prop.

    This is because if we always use collapse dynamically, then the collapsed and expanded versions aren't really separate components anymore. They're two distinct ways of using the same component.

    So in this case, if we’re only using collapse dynamically, we don’t gain much by having separated these components. Yes, it is more organized, but not much simpler.

    But we may mix dynamic and hard-coded usage of this component throughout our app.

    This makes our wrapper component quite useful, since we now have three options to choose from now. Each one very clearly shows the intended usage, making our code easy to understand:

    <ArticlesCollapsed />
    <ArticlesExpanded />
    <Articles :collapse="isCollapsed" />

    To sum up:

    • Replace hard-coded usage with ArticlesCollapsed and ArticlesExpanded
    • Replace dynamic usage with the wrapper component

    Learn more about this pattern in the Clean Components Toolkit.

    🔥 Using Render Functions for Dynamic Component Logic

    Render functions provide a powerful and flexible way to programmatically define the output of components.

    This approach is particularly useful when you need more control over the rendering process than templates offer.

    Consider a scenario where you're building a custom If...Else component that conditionally renders content based on a given condition (we're just doing this for fun, okay?)

    Here's a simplified example of how you might use a render function in an If component:

    export default {
    props: ['val'],
    setup(props, { slots }) {
    return () => {
    const children = [];
    if (props.val && slots.true) {
    children.push(slots.true());
    } else if (!props.val && slots.false) {
    children.push(slots.false());
    }
    return children;
    };
    },
    };

    In this example, the If component takes a val prop to determine which slot to render — true or false. The render function checks props.val and dynamically decides which slot to render based on its value.

    Render functions are especially useful when:

    • You need to programmatically construct component output based on complex conditions.
    • You're building higher-order components that manipulate their children in ways that aren't straightforward with templates.
    • You want to leverage JavaScript's full power to dynamically generate component structures.

    While render functions offer great power and flexibility, they come at the cost of reduced readability and simplicity compared to template syntax.

    So it's generally recommended to use them only when necessary, keeping the balance between functionality and maintainability.

    📜 How to access DOM elements with useTemplateRef

    Learn how to access DOM elements with the useTemplateRef composable.

    I went deep into the useTemplateRef composable, and how it compares to the old way of accessing DOM elements.

    I also share some best practices for using this composable!

    Check it out here: How to access DOM elements with useTemplateRef

    📜 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)

    đź’¬ Technical Debt

    "The code we release will be imperfect. Not buggy. Imperfect. There’s a difference. We know as a fact that some of what our code does will be wrong; we just don’t know exactly what will be wrong. That’s tech debt." — Allen Holub

    đź§  Spaced-repetition: Vue to Web Component in 3 Easy Steps

    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.

    Here's how you can create web components in Vue.

    First, create the custom element from a Vue component using defineCustomElement:

    import { defineCustomElement } from 'vue';
    import MyVueComponent from './MyVueComponent.vue';
    const customElement = defineCustomElement(MyVueComponent);

    Second, register the custom element with the DOM:

    customElements.define('my-vue-component', customElement);

    Third, use the custom element in your HTML:

    <html>
    <head></head>
    <body>
    <my-vue-component></my-vue-component>
    </body>
    </html>

    Now you've got a custom web component that doesn't need a framework and can run natively in the browser!

    Check out the docs for more details on how this works.

    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.