Web Development

Fix Your DX in 2025: My Vanilla Web Component Journey

Tired of framework churn? Discover how I revitalized my team's developer experience (DX) in 2025 by embracing vanilla Web Components. A practical journey.

A

Alex Carter

A senior front-end developer passionate about framework-agnostic, future-proof web architecture.

7 min read18 views

It was late 2024, and my team was drowning. Not in deadlines, but in dependencies. Our package.json file looked less like a manifest and more like a novel, and our CI/CD pipeline had developed a coffee habit, taking its sweet time on every single commit. The developer experience, or DX, was at an all-time low. Every new project kick-off was met with the same weary question: "Which framework this time?"

We were suffering from acute framework fatigue. The promise of rapid development had been replaced by the reality of complex build tools, fragile dependency chains, and a mental overhead that was burning everyone out. That’s when we decided to make a change for 2025. A radical one. We decided to bet on the platform, to go back to basics. This is the story of our journey into vanilla Web Components and how it fixed our DX.

The Framework Fatigue Was Real

To understand why we jumped, you need to see how high the cliff was. Our flagship project, a sprawling customer dashboard, was a Frankenstein's monster of tech. It started in React, but one team had introduced Vue for a specific module, and our design system was built with a different, opinionated React component library. The result? A 500MB node_modules directory, build times that could stretch to 10 minutes, and onboarding a new developer was a week-long ordeal of explaining our specific, convoluted setup.

Every developer felt it. Simple style changes required navigating a labyrinth of scoped CSS-in-JS solutions. Upgrading a single package could trigger a cascade of breaking changes. We were spending more time wrestling with our tools than we were building features for our users. The DX wasn’t just bad; it was actively hostile.

The 'Vanilla' Hypothesis: Could We Just... Not?

During a frustrated retrospective, someone half-jokingly asked, "What if we just used HTML?" It got a laugh, but it also planted a seed. What if we leaned into the web standards that browsers have been building for over a decade? What if we built our foundation on something that wouldn't be obsolete in 18 months? This led us to Web Components.

For those unfamiliar, Web Components are a set of browser-native APIs that let you create custom, reusable, and encapsulated HTML elements. They aren't a framework; they're a standard. They're built on three main technologies:

  • Custom Elements: The ability to define your own HTML tags with custom logic, like <user-profile-card> or <collapsible-panel>.
  • Shadow DOM: This is the magic ingredient for DX. It provides a private, encapsulated DOM tree for your element. Styles and scripts inside the Shadow DOM don't leak out, and styles from the outside don't leak in. Goodbye, CSS specificity wars!
  • HTML Templates: The <template> tag allows you to declare fragments of markup that aren't rendered on page load but can be cloned and used by your components at runtime.

The hypothesis was simple: if we built our core UI elements as vanilla Web Components, they would be framework-agnostic, truly reusable, and free from the tyranny of complex build tools. We could fix our DX by subtracting, not adding.

Dipping Our Toes In: The <modal-dialog> Component

Advertisement

We didn't go all-in at once. We picked a small, universal, and notoriously tricky component to build: a modal dialog. Every project needed one, and they were always a pain to get right, especially concerning accessibility and stacking contexts.

Our first vanilla Web Component looked something like this (simplified for clarity):


class ModalDialog extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        :host {
          /* Styles for the modal container */
        }
        .scrim {
          /* Styles for the background overlay */
        }
      </style>
      <div class="scrim"></div>
      <div class="dialog">
        <slot name="header"></slot>
        <slot></slot> <!-- Default content -->
        <slot name="footer"></slot>
      </div>
    `;
  }

  // ...methods to open(), close(), etc.
}

customElements.define('modal-dialog', ModalDialog);
  

The first time we dropped <modal-dialog>Hello World</modal-dialog> into a plain HTML file and it just worked, it was a revelation. The styles were perfectly scoped. The logic was self-contained. We then dropped the exact same component file into a React project and a legacy jQuery page. It worked everywhere. This was the "aha!" moment. We weren't just building a component; we were building a durable digital asset.

What Actually Changed for Our Developers

Adopting this "Web Component-first" approach had a profound and immediate impact on our team's daily lives.

Onboarding in Hours, Not Days

A new developer joined the team a month into our experiment. Instead of a week of learning our bespoke React/Vue hybrid setup, we told them, "If you know HTML, CSS, and JavaScript, you can be productive today." They were. The component's interface was the HTML tag and its attributes. The documentation was the element itself. The barrier to entry had vanished.

Liberating Tooling and Blazing Builds

For local development on our component library, we often didn't need a build step at all. We just used a simple live-server extension in VS Code. Our CI/CD pipeline, which once groaned under the weight of transpiling and bundling a massive framework app, was now just running tests and copying a handful of JS files. Build times for our component library were measured in seconds.

Unbreakable Styles and Fearless Refactoring

Shadow DOM was the unsung hero. A developer could go into the <modal-dialog> component and completely refactor its internal styles, confident that they wouldn't accidentally break the button styling on the marketing site. This psychological safety made everyone more willing to make improvements and less afraid of the codebase.

A simplified comparison of our development workflows.
Aspect Old Way (Framework-First) New Way (Web Component-First)
Dependencies Massive (React, Vue, CSS-in-JS libs, etc.) Minimal to none
Reusability Locked into a specific framework ecosystem Universal (works in any framework or none)
Styling Complex, prone to global conflicts Encapsulated and predictable via Shadow DOM
Onboarding Requires deep framework and tooling knowledge Requires only standard web skills (HTML/CSS/JS)

It's Not a Silver Bullet: The Hurdles and Realities

Our journey wasn't without its challenges. Moving to Web Components isn't a panacea for all development woes.

State management is the big one. Web Components are great for self-contained UI, but for complex applications, you still need a way to manage shared state. We ended up using a simple pub/sub event bus for communication between components and a lightweight state library for one of our more complex apps. The key was that this was a conscious choice, not a default imposed by a framework.

Server-Side Rendering (SSR) can also be tricky. While Declarative Shadow DOM is making this much easier, it's not as mature as the SSR solutions in frameworks like Next.js or SvelteKit. For our public-facing, SEO-critical sites, we still use a framework for the 'shell' but populate it with our standard Web Components on the client side.

Finally, there's a bit more boilerplate to writing a vanilla component compared to the slick syntax of something like Svelte or Vue. We mitigated this by creating our own simple base classes, but libraries like Lit are a fantastic, lightweight option that provides helpful sugar without locking you in.

Our 2025 DX Verdict: A Breath of Fresh Air

Has our DX been fixed? Absolutely. We didn't throw away our frameworks—they still serve a purpose, especially for application routing and structure. But we shifted our foundation. We now build from the bottom up with durable, standard, and simple Web Components.

Our codebase is simpler, our builds are faster, our teams are more aligned, and our developers are genuinely happier. We've traded the churn of the framework-of-the-month for the stability of the web platform. In a world of ever-increasing complexity, this simplification has been the single greatest improvement to our developer experience.

If your team is feeling the framework fatigue, I urge you to give it a try. Pick one small, leaf-node component and build it with vanilla JavaScript. You might just be surprised at how liberating it feels to just build for the web.

Tags

You May Also Like