Exclusive tips every week

Join 11,067 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

    🔥 (#175) Reactivity and Callbacks

    Hey all,

    I hope you're doing well! This week I'm enjoying some summer vacation.

    But I do have some tips for you, as always.

    Also, don't forget that Nuxt Tips Collection is coming soon, on August 5th! You can sign up here for a special launch day discount if you're interested.

    I've already been getting some great feedback from my beta testers, and Alex Lichter (part of the Nuxt team) is doing a technical review of all the tips.

    Enjoy the tips, and enjoy your week!

    — Michael

    🔥 Reactivity and Callbacks

    Callback is a bit of a dirty word in Vue, but there are great use cases for them.

    Consider a scenario where a parent component needs to react to changes in its children's state. You can use a reactive object provided by the parent and injected by the children to keep track of changes.

    Here's an example:

    // Parent component
    const sharedState = reactive({});
    provide('sharedState', sharedState);
    // Child component
    const sharedState = inject('sharedState');

    When a child component updates a property of sharedState, Vue's reactivity system ensures that any effects or computed properties that depend on sharedState are automatically re-evaluated.

    You can use callbacks to allow child components to register themselves with the parent or to signal the parent to perform an action.

    Here's how you might implement a callback with provide and inject:

    // Parent component
    const registerChild = (child) => { /* ... */ };
    provide('registerChild', registerChild);
    // Child component
    const registerChild = inject('registerChild');
    registerChild(/* child details */);

    This pattern is powerful for creating complex interactions between components while keeping the logic encapsulated and manageable.

    It's especially useful in the Compound Components pattern.

    🔥 Smooth dragging (and other mouse movements)

    If you ever need to implement dragging or to move something along with the mouse, here's how you do it:

    1. Always throttle your mouse events using requestAnimationFrame. Lodash's throttle method with no wait parameter will do this. If you don't throttle, your event will fire faster than the screen can even refresh, and you'll waste CPU cycles and the smoothness of the movement.
    2. Don't use absolute values of the mouse position. Instead, you should check how far the mouse has moved between frames. This is a more reliable and smoother method. If you use absolute values, the element's top-left corner will jump to where the mouse is when you first start dragging. Not a great UX if you grab the element from the middle.

    Here's a basic example of tracking mouse movements using the Composition API. I didn't include throttling in order to keep things clearer:

    // In your setup() function
    window.addEventListener("mousemove", (e) => {
    // Only move the element when we're holding down the mouse
    if (dragging.value) {
    // Calculate how far the mouse moved since the last
    // time we checked
    const diffX = e.clientX - mouseX.value;
    const diffY = e.clientY - mouseY.value;
    // Move the element exactly how far the mouse moved
    x.value += diffX;
    y.value += diffY;
    }
    // Always keep track of where the mouse is
    mouseX.value = e.clientX;
    mouseY.value = e.clientY;
    });

    Here's the full example. You can check out a working demo here:

    <template>
    <div class="drag-container">
    <img
    alt="Vue logo"
    src="./assets/logo.png"
    :style="{
    left: `${x}px`,
    top: `${y}px`,
    cursor: dragging ? 'grabbing' : 'grab',
    }"
    draggable="false"
    @mousedown="dragging = true"
    />
    </div>
    </template>
    <script setup>
    import { ref } from "vue";
    const dragging = ref(false);
    const mouseX = ref(0);
    const mouseY = ref(0);
    const x = ref(100);
    const y = ref(100);
    window.addEventListener("mousemove", (e) => {
    if (dragging.value) {
    const diffX = e.clientX - mouseX.value;
    const diffY = e.clientY - mouseY.value;
    x.value += diffX;
    y.value += diffY;
    }
    mouseX.value = e.clientX;
    mouseY.value = e.clientY;
    });
    window.addEventListener("mouseup", () => {
    dragging.value = false;
    });
    </script>

    🔥 Aria roles you didn't know you needed

    Aria roles are used to tell a screenreader what an element is for.

    This is really important when the native HTML element just doesn't exist (eg. roles like toolbar and alert) or when you're using a different HTML element for design or technical reasons (eg. wrapping a radio button to style it).

    But please, remember that you should always use the semantic element where you can. This is always the best and most effective solution.

    There are six different categories of aria roles:

    1. Widget - roles like button, checkbox, separator, tab, or scrollbar
    2. Composite - roles like combobox and listbox (these are for dropdown menus), radiogroup, or tree
    3. Document structure - this includes article, presentation, figure, feed, and directory
    4. Landmark - banner, main, navigation, and region are roles in this category
    5. Live region - alert, log, marquee, and status are roles that might update with real-time information
    6. Window - alertdialog and dialog are the only two roles in this category

    You can check out the full list here: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques#roles

    🎙️ #017 — Tiptap and Vue.js (with Vanessa Otto)

    In this episode of DejaVue, Alex and Michael are joined by Vanessa Otto, a Senior Engineer at GitLab and previously the head of Frontend at Zavvy.

    After discussing Vanessa's co-host role in the German Working Draft podcast, it all revolves around the headless editor "Tiptap". From hearing why Vanessa chose it instead of other editors and her research around editors, Tiptap's integration with Vue, and what the "headless" part of the editor adds to it, over to which use cases are ideal for Tiptap.

    And yes, an example repository is included so you can convince yourself of the easiness! Enjoy the episode!

    Watch on YouTube or listen on your favourite podcast platform.

    Chapters:

    In case you missed them:

    📜 Ignorable Watch

    This article is a great look at how you can use the flush option with watchers to create some pretty complex and useful behaviours.

    I don't want to spoil it for you though. Just read the article!

    Check it out here: Ignorable Watch

    📜 Coding Better Composables: Options Object (5/5)

    I teamed up with Vue Mastery to create this series on coding better composables.

    In this series we cover five different patterns.

    For each, we show how you can implement it and then we see it in action with a composable from VueUse.

    This fifth and final article of the series shows how we can use the Async Without Await pattern to simplify our composables.

    Check it out here: Coding Better Composables: Options Object (5/5)

    📅 Upcoming Events

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

    PragVue 2024 — (September 17, 2024)

    The first Czech Vue.js conference, taking place in Cinema City - Nový Smíchov

    Check it out here

    Vuejs.de Conf — (October 8, 2024 to October 9, 2024)

    A community-driven Vue conference in Germany. Listen to great talks from great speakers and meet the wonderful VueJS Community.

    Check it out here

    Vue Fes Japan 2024 — (October 19, 2024)

    Check it out here

    VueConf Toronto 2024 — (November 18, 2024 to November 20, 2024)

    My favourite Vue conference, in my own backyard! A three-day event with workshops, speakers from around the world, and socializing.

    Check it out here

    💬 Things

    "Things aren’t always #000000 and #FFFFFF." — undefined

    🧠 Spaced-repetition: Make Testing Easy

    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.

    Testing is important to do, but it can be hard to do.

    In my experience, good architecture lends itself to easy-to-write tests (or at least, easier-to-write). The inverse is also true, that difficult-to-write tests are typically a symptom of poor architecture.

    Of course, sometimes tests are just hard to write, and there’s no way around it.

    The best thing we can do is borrow a tool from mathematics and science, and transform a difficult problem into an easier but equivalent one:

    • Humble Components — UI is notoriously hard to test, and always has been. So keep as much in Humble Components, components that only receive props and emit events and nothing else. By making our UI as simple as possible we also make it much easier to test.
    • Extract logic to composables — And I mean all of your logic. Components (that aren’t Humble) should only contain the bare minimum to connect all the different composables together. Think of them as Controller Components, the “C” in MVC.
    • Composables are thin layers of reactivity — The easiest thing in the world to test are pure functions that have no dependencies. If you can make the majority of your codebase simple JS or TS code, you’ve already won. Composables then become simple wrappers that add a layer of reactivity to this business logic.

    Michael Hoffman curates a fantastic weekly newsletter with the best Vue and Nuxt links.

    Sign up for it here.



    p.s. I also have four products/courses: Clean Components Toolkit, Vue Tips Collection 2, Mastering Nuxt 3, and Reusable Components

    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.