🔥 (#160) Magical components, pseudo-selectors, and the Vite ecosystem

What's up?

I'll be giving a talk at Vue.JS Live on April 25th.

You can check it out here: https://vuejslive.com/

Other than that, enjoy your tips and the rest of your week!

— Michael

null

🔥 Creating Magic with Context-Aware Components

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.

🔥 Special CSS pseudo-selectors in Vue

If you want some styles to apply specifically to slot content, you can do that with the :slotted pseudo-selector:

<style scoped>
/* Add margin to <p> tags within the slot */
:slotted(p) {
margin: 15px 5px;
}
</style>

You can also use :global to have styles apply to global scope, even within the <style scoped> block:

<style scoped>
:global(body) {
margin: 0;
padding: 0;
font-family: sans-serif;
}
</style>

Of course, if you have lots of global styles you want to add, it's probably easier to just add a second <style> block:

<style scoped>
/* Add margin to <p> tags within the slot */
:slotted(p) {
margin: 15px 5px;
}
</style>
<style>
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
</style>

Check out the docs for more info.

🔥 Overriding styles of a child component — the right way

Scoped CSS is fantastic for keeping things tidy and not accidentally bleeding styles into other parts of your app.

But sometimes, you need to override the styles of a child component and break out of that scope.

Vue has a :deep selector just for this:

<style scoped>
/* Override CSS of a child component
while keeping styles scoped */
.my-component :deep(.child-component) {
font-size: 24px;
}
</style>

In Vue 2 this has a slightly different syntax depending on which CSS pre-processor you're using:

<style scoped>
/* When using SASS */
.my-component ::v-deep .child-component {
font-size: 24px;
}
/* Everything else */
.my-component >>> .child-component {
font-size: 24px;
}
</style>

Yes, I have previously covered why you shouldn't do this, but overriding styles can be the best solution (we don't believe in "best practices" here).

📜 The Vite Ecosystem

Vite has taken web development tooling to a new level.

This article explores all of the different tools Vite uses and interacts with, and shows just how much it affects the web development community.

It's very cool to see a project that started out in Vue-land gain wide adoption like this!

Check it out here: The Vite Ecosystem

đź’¬ Data structures

"Bad programmers worry about the code. Good programmers worry about data structures and their relationships." — Linus Torvalds

đź§  Spaced-repetition: Default Content with Nested Slots

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.

If you have multiple levels of nested slots, it's possible to have defaults at each level:

<!-- Parent.vue -->
<template>
<Child>
<slot>
We're in the Parent!
</slot>
</Child>
</template>
<!-- Child.vue -->
<template>
<div>
<slot>
We're in the Child!
</slot>
</div>
</template>

The slot content provided at the highest point in the hierarchy will override everything below it.

If we render Parent, it will always display We're in the Parent. But if we render just the Child component, we get We're in the Child!.

And if the component rendering the Parent component provides slot content, that will take precedence over everything:

<!-- Grandparent.vue -->
<template>
<Parent>
Haha this content rules them all!
</Parent>
</template>



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