August 28, 2025
Advanced
Generic Components: The Art of Not Reinventing the Wheel (Part 1)
"If you're copying and pasting code, you're doing something wrong" - Every senior developer, always.
What the heck are Generic Components?
First of all, I need to make one thing very clear: generic components are not a formal computer science concept. There's no academic paper or sacred book that defines what a generic component is. This is more one of those best practices that the developer community created in order to keep its sanity.
Imagine you're building a house. You're not going to invent a new way to make a door every time you need one, right? You use the same pattern, but you adapt the size, the color, the material. That's exactly what we do with generic components.
But let's go beyond the house analogy. Think about how you organize your kitchen: you have a set of knives, but each one has a specific purpose. The bread knife is different from the meat knife, but both follow the same basic cutting principle. Generic components work the same way: they keep their essence, but they adapt to the context.
The key here is to understand that we're not creating a component that solves every problem in the world. We're creating a component that solves a specific problem in a reusable way. It's the difference between a Swiss Army knife (which does everything, but nothing well) and a set of specialized knives (each of which does one thing perfectly).
Why are Generic Components such a Lifesaver?
1. DRY (Don't Repeat Yourself)
If you've ever written "don't repeat code" somewhere in your project, congratulations! You've already understood half the concept. Generic components are the materialization of this philosophy.
But what does this mean in practice? Imagine you have a user registration form and another product registration form. Both need text fields, validation, and action buttons. Without generic components, you end up duplicating all that logic. With generic components, you create a reusable text field and a reusable button, and you only need to worry about the specific logic of each form.
DRY isn't just about not repeating code, it's about not repeating problems. When you have a bug in a duplicated component, you have to fix it in every place. With generic components, you fix it once and solve it everywhere.
But here's the crucial point: DRY doesn't mean "never repeat anything". Sometimes, duplicating a bit of code is better than creating a generic component that's hard to understand and maintain. The rule is: duplicate when duplication is clearer than abstraction.
2. Maintenance is a Delight
When you need to change something, you change it in just one place. You don't have to hunt down every button in the project to change its color. It's like having a central switch that controls all the lights in the house.
But let's think about a real scenario: imagine your designer decides that all primary buttons should have a more subtle shadow. If you have buttons scattered across 20 different components, you're going to spend an entire afternoon making the same change. With a generic component, you change it in one place and all the buttons update automatically.
And it's not just about visual changes. Think about accessibility: if you need to add screen reader support to all buttons, doing it in a generic component is much more efficient than going after each individual instance.
Maintenance also includes debugging. When you have a problem with a specific behavior, it's much easier to investigate a centralized component than to track down the same problem in 15 different places. You can put logs, breakpoints, and tests in just one place.
3. Visual Consistency
Your users won't get confused seeing different buttons on every page. It's like having a design system without having to pay a fortune for a consultancy.
Visual consistency goes far beyond "looking pretty". It directly affects the usability of your application. When a user sees a blue button on one page, they expect blue buttons on other pages to behave the same way. Generic components ensure that this expectation is always met.
In addition, consistency makes onboarding new developers to the team easier. They don't have to learn 15 different ways to do the same thing. And when you're working as a team, everyone follows the same standards, which reduces confusion and improves code quality.
But consistency also has a downside: if you make a mistake in the generic component, that mistake propagates to every place where it's used. That's why tests are essential for generic components.
Practical Examples (Because theory without practice is just empty talk)
React: The King of Components
Let's start with a simple but powerful example. Imagine you have buttons scattered all over the application:
// ❌ Before: Each button was an only child
<button style={{ backgroundColor: "#007bff", color: "white", padding: "10px 20px" }}>
Salvar
</button>
<button style={{ backgroundColor: "#dc3545", color: "white", padding: "10px 20px" }}>
Deletar
</button>
Now, with a generic component:
// ✅ After: One component that solves everything
<Button variant="primary">Salvar</Button>
<Button variant="danger">Deletar</Button>
The Button component internally manages all the styles, variants, and behaviors. You only need to worry about what the button should do, not what it should look like.
Angular: The Framework that Likes to Decorate Everything
In Angular, the situation is similar. You might have inputs with validation scattered across several forms:
// ❌ Before: Each input was a unique work of art
<input type="text" placeholder="Nome" class="form-control" [(ngModel)]="nome">
<div class="invalid-feedback" *ngIf="nomeInvalido">Nome é obrigatório</div>
<input type="email" placeholder="Email" class="form-control" [(ngModel)]="email">
<div class="invalid-feedback" *ngIf="emailInvalido">Email inválido</div>
With a generic component:
// ✅ After: One input that solves everything
<app-form-input placeholder="Nome" [(value)]="nome" [validation]="validarNome"></app-form-input>
<app-form-input type="email" placeholder="Email" [(value)]="email" [validation]="validarEmail"></app-form-input>
The app-form-input component internally manages the validation, the error styles, and the input logic. You only need to pass the specific validation function for each field.
Conclusion: Why Is It Worth the Effort?
Generic components may seem like extra work at first; you have to think about the abstraction, create flexible interfaces, and test different scenarios. But, as we saw in the examples, the return is immediate and long-lasting.
What you gain:
- Time: No more rewriting the same logic 15 times
- Quality: Fewer bugs because the logic is centralized
- Flexibility: Global changes in a single place
- Team: New devs learn faster
What you lose:
- A few hours at the start to create the component
- The "freedom" to make each button differently (spoiler: that's not freedom, it's a mess)
It's like investing in a quality tool: it costs a little more upfront, but you use it for years and it never lets you down. Generic components are those tools of frontend development.
In the next part, we'll talk about when to use generic components, when NOT to use them, and the famous case of the generic filters that went completely wrong. Stay tuned!
Post Author

Leonardo Henrique
E aí! Sou o Leonardo Henrique, mas muita gente me conhece como "Leozinho do Front" — culpa da minha paixão por Front-End. Trabalho como desenvolvedor Full Stack, com bastante experiência em Angular, um carinho especial por React e, agora, me aventurando com Vue. Curto demais jogos e animes, e um dia ainda quero me aventurar na área de games.