Back to notes

Essays

Designing Angular components that survive product complexity

Components last longer when their boundaries match responsibilities users and teams already recognize.

AngularDesign SystemsComplex UX

The component that looks reusable on day one can become the component everyone avoids by month six. The usual reason is that it was reusable visually, not conceptually.

A product surface does not grow evenly. One team adds permissions. Another adds bulk actions. A third needs review states. Someone needs a compact variant for a dense table. If the original component was just a styled box, every new requirement becomes an argument about where behavior belongs.

I prefer components with boundaries that match product responsibilities: choosing an item, comparing records, reviewing a recommendation, confirming a risky action, summarizing a state. Those boundaries give the component a reason to exist as the product changes.

This is also how I think about design systems. They should not force every screen into a generic shape. They should provide strong primitives and product-aware patterns that make teams faster while keeping behavior consistent.

In Angular, I like templates that stay readable because the component has already done the work of naming the state. A template should not look like a puzzle of booleans. It should read like the interface: this is pending review, this action is blocked, this item is selected, this empty state is filtered.

The tradeoff is that you sometimes write a little more structure up front. I am comfortable with that when the structure maps to real product complexity. I am not comfortable with abstractions that exist only because a component might someday be reused.

Surviving complexity is not about predicting every future requirement. It is about choosing boundaries that make the next requirement less surprising.