Every PR contained a new button variant. Every form had its own styles. Juniors spent more time on CSS than on business logic.
I looked at our Vue.js codebase. We had three different modal implementations. Four table styles. Dozens of form variations. Each developer had their own interpretation of "our design".
The problem wasn't talent. The problem was the absence of constraints.
The Choice: Build or Adopt
We could have created our own design system. Documented every component. Written guidelines. Maintained an internal library.
I did the math. Building a solid design system: 3-4 months minimum. Maintaining it: one person part-time permanently. Documenting it properly: more weeks.
Or: adopt an existing library and adapt it to our brand.
I chose ElementPlus. Not because it's the best design system in the world. Because it was mature, well-documented, and perfectly integrated with Vue 3.
The Two-Phase Integration
Phase 1: Theming (Week 1)
The first mistake would be using ElementPlus as-is. Our users would immediately see it's "a template".
I created a theming layer. CSS variables for colors. Tokens for spacing. Overrides for the most visible components.
// variables.scss
$--color-primary: #1a5f4a;
$--color-success: #2d7a5e;
$--border-radius-base: 6px;
$--font-family: 'Inter', sans-serif;
The result: ElementPlus with our visual identity. Users don't see "a framework". They see "our application".
Phase 2: Wrappers (Week 2)
The second mistake would be using ElementPlus components directly everywhere. If tomorrow we switch libraries, we'd have to modify hundreds of files.
I created wrapper components. AppButton encapsulates el-button. AppInput encapsulates el-input. These wrappers add our conventions: default sizes, standard behaviors, simplified props.
<script setup lang="ts">
defineProps({
variant: { type: String, default: 'primary' },
size: { type: String, default: 'default' },
loading: { type: Boolean, default: false }
})
</script>
<!-- AppButton.vue -->
<template>
<el-button
:type="variant"
:size="size"
:loading="loading"
v-bind="$attrs"
>
<slot />
</el-button>
</template>
Now developers use AppButton, not el-button. The underlying library becomes an implementation detail.
What Actually Changed
Before: a junior took 2-3 hours to create a form with validation. They had to handle styles, error states, responsive layouts.
After: the same form takes 30-45 minutes. They assemble components. They focus on business logic.
- UI PRs are 60% smaller (less custom CSS)
- Visual bugs dropped (components tested by the community)
- Onboarding new devs is faster (external documentation)
- Visual consistency is guaranteed (framework constraints)
Pitfalls to Avoid
I made mistakes. Here are three.
Overriding too many styles. Initially, I wanted to customize everything. Result: we lost framework updates. Now I only override essentials: colors, typography, border-radius.
Ignoring native accessibility. ElementPlus handles ARIA, focus management, keyboard navigation. When I created custom components, I forgot all that. Standard components are often more accessible than our creations.
Not documenting conventions. Even with a design system, devs have questions. "Which variant for this button?" "What modal size?" I created a 2-page internal guide. It eliminated 80% of questions.
The Takeaway
For months, I believed every project deserved its own custom design system. That frameworks were for people who couldn't do CSS.
I was wrong. A design system is productive constraints. Decisions already made. Time saved to focus on what matters: business value.
Our juniors no longer debug CSS. They ship features. And our application has never been more visually consistent.