Skip to content
Strynal, Digital Agency

Engineering 6 min read

Web Components Explained

What Web Components are, when they outperform a framework, and when they don't. Covers Custom Elements, Shadow DOM, Lit, and the interoperability case.

By Strynal Team

Web Components have been around long enough to be called production-ready, yet most teams still reach for React or Vue by reflex. That’s often the right call. But there’s a class of problem where native browser primitives serve better, and knowing the difference is a practical skill.

What Web Components actually are

Web Components is the umbrella term for three browser standards that let you build encapsulated, reusable HTML elements without a framework.

  • Custom Elements let you register a new HTML tag (<my-button>, <product-card>) backed by a JavaScript class. The browser treats it like any native element: you can query it with document.querySelector, give it attributes, and slot it into markup.
  • Shadow DOM attaches a private DOM tree to your element. CSS inside the shadow boundary doesn’t leak out, and external styles don’t leak in. Encapsulation by default.
  • HTML Templates (<template> and <slot>) give you inert markup that is parsed but not rendered, ready to clone into a shadow tree.

Together, they let you ship <color-picker> or <data-table> as a file (or an npm package) that works in React, Vue, Svelte, or plain HTML without modification. That interoperability is the practical point.

A minimal custom element

class GreetUser extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<p>Hello, ${this.getAttribute('name') || 'stranger'}</p>`;
  }
}
customElements.define('greet-user', GreetUser);

Now <greet-user name="Zeki"></greet-user> works in any HTML page with no build step. Shadow DOM would let you scope styles to it; templates let you define its structure declaratively. These three primitives compose into a full component model.

When Web Components make sense

The browser-native case is strongest in two scenarios.

Cross-framework component libraries. If your organization runs React on the marketing site, Vue in the internal tool, and Angular in the enterprise portal, a shared Web Component works everywhere. Maintaining three wrappers for a design system button is expensive; one native implementation is not.

Long-lived embeds and widgets. A feedback widget, a booking form, a chat button: these get embedded in sites you don’t own and can’t predict. Shadow DOM isolation means the host page’s CSS won’t touch your widget. A React component has no such guarantee; its styles can collide with anything in the host environment.

There is also a quieter case: sites where JavaScript is minimized by design. A few native components can add interactivity without pulling in a framework runtime. That is the premise behind progressive enhancement, and Web Components fit it naturally.

Web Components shine wherever the host environment is unpredictable: cross-framework systems, third-party embeds, and design tokens that need to outlast any single framework choice.

Where Web Components fall short

Be honest about the trade-offs.

No server-side rendering by default. The standard is inherently client-side. Shadow DOM is rendered in the browser; there is no HTML stream coming off the server with the shadow tree already populated. Declarative Shadow DOM lets you ship shadow markup in static HTML, but it is newer and needs careful handling in your rendering pipeline.

State management is manual. React, Vue, and Svelte have reactivity baked in. Custom Elements give you lifecycle callbacks and attribute-change observers. That is enough for simple, leaf-level components, but wiring up complex state across a tree gets tedious without a library on top.

Tooling and developer experience lag. TypeScript support, hot module replacement, and template syntax require extra setup compared to established frameworks. Libraries like Lit smooth most of this over, but you are adding a layer to get back to parity.

They are elements, not applications. Web Components work well as leaves in a component tree. Building an entire single-page app with them is possible but unusual, and the developer experience is rougher than a framework built for that use case.

This is the core trade-off: native interoperability and isolation, at the cost of reactivity and tooling maturity. When interoperability is the hard constraint, Web Components win. When iteration speed and team familiarity matter more, a framework wins. That decision should be deliberate, not reflexive.

Web Components alongside frameworks

The more interesting question is whether to use Web Components instead of a framework or alongside one. The answer is usually “alongside.”

A common pattern: React or Astro handles pages, routing, and application state. A handful of custom elements handle embeds, design tokens, or UI components that must cross framework boundaries. The React tree and the Web Component coexist in the same page without conflict.

Astro’s islands architecture is a useful mental model here. Each interactive island is an isolated unit with its own rendering context. A Web Component slot fills the same role: a scoped, framework-agnostic chunk. We covered how that thinking shapes build decisions in our guide to rendering strategies.

If you are choosing between React and a leaner option for a content-heavy site, the comparison of React and Astro is worth reading before the Web Components question even comes up. Often the architecture choice is upstream of the component primitive choice.

Should you use a Web Components library?

Plain custom elements are verbose. The lifecycle callbacks (connectedCallback, disconnectedCallback, attributeChangedCallback) repeat across every component. Two libraries are worth knowing.

Lit (from Google) is the most widely used. It adds a declarative template syntax, reactive properties, and a signal-style update cycle. The output is still a native custom element; Lit is a thin layer that makes authoring less tedious. Bundle size is around 5 KB.

FAST (from Microsoft) targets design systems at scale. More opinionated and heavier, but it powers the Fluent UI design system, which is evidence it holds up under real organizational complexity.

For most use cases, Lit is the right starting point. If you are rolling a design system that several teams will consume across different stacks, evaluate FAST before committing.

How Strynal approaches Web Components

Our default for new websites and apps is Astro with framework islands where interactivity is needed. Web Components enter the picture when a build has a genuine cross-framework or long-lived-embed constraint: a shared UI kit for a multi-platform client, a widget deployed across properties the client doesn’t fully own, or a component that needs to outlast the current framework decision.

We don’t treat them as a progressive signal. The question is what the project’s constraints actually call for. Sometimes it is Lit custom elements. Sometimes it is React with a shared design token library. The answer depends on who operates the thing after we ship it and how many different environments it needs to survive in.

If you are working through an architecture decision and not sure where native browser primitives fit versus a framework, that is exactly the kind of scoping conversation we have early. No fabricated roadmap required: just the constraints on the table and the right tool for them.