Capítulo 12 de 17

Chapter 12: Component API Conventions

Core Idea

A design system lives or dies on whether its components share a predictable, consistent API — the same prop names meaning the same thing across every component is what lets a team learn the system once and apply that knowledge everywhere.

Key Concepts

  • Consistent variant/size/tone props: most mature systems converge on a small, shared vocabulary — variant (visual style: primary/secondary/ghost), size (sm/md/lg), tone or color (semantic intent: danger/warning/success) — applied identically across Button, Badge, Alert, etc.
  • Compound components: splitting a complex component into a set of related sub-components that share implicit context (Tabs.Root/Tabs.List/Tabs.Trigger/Tabs.Content) instead of one component with a huge flat prop list — gives consumers layout/composition flexibility the monolithic version can't.
  • Slots / render props / asChild: escape hatches that let a consumer inject custom content or change the rendered element without forking the component — asChild (Radix/Base UI's pattern, clone props onto a custom child) and named slot props (leadingIcon, renderItem) are the two dominant approaches.
  • Controlled vs. uncontrolled state: supporting both an uncontrolled mode (internal state, defaultValue) and a controlled mode (value + onChange) is close to universal in mature component libraries — it's what lets the same component work for both simple and state-managed-elsewhere use cases.
  • What Radix/Base UI/shadcn do well: anatomy-first composition (named parts, not monolithic props), styling via data attributes (data-state) instead of JS-driven class toggling, and accessibility handled internally by default — see radix-primitives-docs and base-ui-docs for the concrete API contracts.

Mental Models

A new component should feel like it was designed by the same person who designed the last one. If a developer has to check docs for whether this component's size prop is size or variant or sizeVariant, the API convention layer has failed.

Prefer composition (compound components, slots) over prop explosion. A component accumulating dozens of boolean/enum props to cover every layout variation is a sign it should be decomposed into composable parts instead.

Anti-patterns

  • Prop naming drift: color on one component, variant on another, theme on a third, all meaning roughly the same thing — forces consumers to re-learn the API per component.
  • Monolithic mega-components: a single <Table> component with 40 boolean props trying to cover every table feature, instead of composable sub-parts (see tanstack-table-docs for the composable, headless alternative).

Key Takeaways

  1. Standardize a small shared vocabulary (variant/size/tone) across every component — this consistency is worth more than any individual component's cleverness.
  2. Use compound components and slots for complex components instead of growing a flat prop list indefinitely.
  3. Support both controlled and uncontrolled usage by default — it costs little upfront and avoids a breaking API change later.
  4. Study existing headless/unstyled libraries (radix-primitives-docs, base-ui-docs) as reference implementations of these conventions rather than reinventing them from scratch.

Connects To

  • Ch 11 (Design Tokens): size/tone props are usually thin wrappers over token values.
  • radix-primitives-docs, base-ui-docs, shadcn-ui-docs: concrete, production-grade examples of these API conventions.