The problem
Imagine you are tasked with rendering a list of articles. Seems easy enough, you've done this a lot. You quickly come up with this solution:
<div class="articles">
<div *ngFor="let article of articles">
{{ article.tittle }}
</div>
</div>
.articles {
display: flex;
justify-content: space-between;
align-items: center;
}
All is well in the world, the list is displayed correctly, and you move on with your life 💪
The Next Day
Next day, there is a new requirement. On a different page of the application you have to render the same articles, but now in a grid layout 🧱
We want to reuse the existing component, because the only difference is the layout of the list.
You might think of the following solutions:
- create
@Input
which will drive the behaviour of dynamically styling the component to render either a list or a grid layout - create a
<articles-grid>
and<articles-list
> components which will reuse the article card.
Both of this solutions will work, but they are needlessly complicated 😱
We either have to expand the component API to accommodate different layouts or create layout components that differ by just a couple lines of CSS.
The solution
What about a different approach? If we get rid of the wrapper .articles
div and style the :host
element directly, we will be able to override this layout styling as needed in the parent component.
Let's see it in action.
First, we remove the not needed wrapper div:
<div *ngFor="let article of articles" class="article">
{{ article.tittle }}
</div>
Next, we update the CSS to target the :host
element of the component:
:host {
display: flex;
justify-content: space-between;
align-items: center;
}
And that's it! With this simple change, we open up lost of possibilities for different layouts, which we can achieve with just CSS.
That's because the :host
selector is the only part of the component which can be styled in the parent component.
Now this will continue to render the default flex layout:
<app-articles></app-articles>
But this will override the flex layout with grid:
<app-articles class="grid"></app-articles>
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
In the future if there is a new requirement to render the article list in a different layout, it's as easy as creating a new CSS class and styling it.
<app-articles class="two-column-grid"></app-articles>
<app-articles class="five-column-grid"></app-articles>
<app-articles class="responsive-grid"></app-articles>
...etc
The recommendation
❌ Avoid using top level container elements just to style them
✅ Style :host
component when possible to make the component more reusable
Hope you're having a great one, and I'll see you for more web dev posts in the future 🥳
Top comments (0)