A pattern is emerging across frameworks: organize UIs as trees of self-contained components. React does it with JSX. Web Components do it with custom elements. Angular 2 (being developed now) is redesigning around components. This convergence is interesting—but the implementations are incompatible.
Why Components Won
The component model solves problems that templates and controllers don't:
Encapsulation. A component owns its markup, styles, and behavior. Everything related to "user profile card" lives together, not scattered across templates/, styles/, and controllers/.
Reusability. Build a button component once, use it everywhere with different props/attributes. No copying template snippets or sharing CSS classes carefully.
Composition. Build complex UIs by composing simple components. <UserProfile> contains <Avatar>, <UserStats>, and <ActionButtons>. Each can be tested and understood independently.
Maintainability. Changes are local. Modifying how buttons work means editing one component, not grepping for all uses of .btn class.
This model isn't new—desktop GUI frameworks have used it for decades. Web is finally catching up.
The Three Approaches
React Components
var UserCard = React.createClass({
render: function() {
return (
<div className="user-card">
<Avatar user={this.props.user} />
<h2>{this.props.user.name}</h2>
</div>
);
}
});
Components are JavaScript classes. JSX provides template syntax. Props are immutable inputs. State is managed internally. One-way data flow.
Web Components
var UserCard = document.registerElement('user-card', {
prototype: Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
this.innerHTML = `<div>...</div>`;
}
}
})
});
Components are custom HTML elements. Shadow DOM provides encapsulation. Browser-native, no framework needed. But verbose API and limited browser support.
Angular 2 Components (proposed)
@Component({
selector: 'user-card',
template: `<div>...</div>`
})
class UserCard {
constructor(user) {
this.user = user;
}
}
Components are ES6 classes with decorators. Templates are strings or separate files. Two-way binding by default. Framework-specific but comprehensive.
The Incompatibility Problem
We've converged on "components are good" but diverged on implementation. React components don't work in Angular. Web Components work anywhere but are lowest common denominator. Each framework's components use different lifecycles, APIs, and patterns.
This fragmentation means:
- Component libraries are framework-specific
- Moving between frameworks means rewriting components
- Sharing components across projects requires the same framework
- The "write once, use everywhere" promise doesn't materialize
Web Components were supposed to solve this—browser-native, framework-agnostic components. But the API is low-level and verbose. Framework components are easier to use but create lock-in.
The Styling Question
How do components handle CSS? Options:
Global CSS with naming conventions
.UserCard { }
.UserCard__avatar { }
BEM-style naming prevents collisions, but it's convention, not enforcement. Careful discipline required.
Inline styles
var style = {
backgroundColor: 'blue',
padding: '10px'
};
<div style={style}>
React encourages this. Styles are component-local by default. But loses CSS power (media queries, pseudo-selectors).
Shadow DOM
var shadow = element.createShadowRoot();
shadow.innerHTML = '<style>.title { }</style><div class="title">Hi</div>';
Truly scoped styles. But requires Web Components, which means limited browser support and polyfill overhead.
CSS Modules (emerging)
import styles from './UserCard.css';
<div className={styles.title}>
Build-time transformation makes CSS modular. Promising but requires tooling.
None of these is clearly best. Each trades off power, simplicity, and tooling requirements.
The Data Flow Debate
Components need data. How it flows matters:
One-way (React): Parent passes props to children. Children notify parents via callbacks. Explicit, predictable, verbose.
Two-way (Angular): Changes in parent update child, changes in child update parent. Implicit, convenient, creates coupling.
React's one-way flow makes data flow obvious but requires more boilerplate. Angular's two-way binding is concise but can create mysterious bugs when data changes from unexpected places.
There's tension between explicitness and convenience. Teams value these differently.
Looking Forward
Component architecture is here to stay. The question is whether we consolidate on one approach or live with framework-specific components indefinitely.
Web Components could be the consolidation point, but they need:
- Better API (current is too low-level)
- Universal browser support
- Framework integration patterns
Framework-specific components will likely dominate for years. Web Components might become an interop layer later.
For now, choose a framework, embrace its component model, and accept the lock-in. The component pattern is more important than the specific implementation.
Resources: