Vue

4 / 10

Vue

Designing Vue Components People Enjoy Using

Props in, events out, slots for flexibility. API design habits that keep components reusable instead of configurable to death.

A component is an API with a template attached, and the same taste that makes good functions makes good components: clear inputs, predictable outputs, and flexibility where variation is real rather than imagined. Components rot in a specific way, one boolean prop at a time, and the antidote is designing the contract deliberately.

The contract: props down, events up

Props are inputs the component never mutates; events announce things the parent might care about. State that both parent and child care about belongs to the parent, synced with v-model, which in Vue 3 is pleasantly explicit via defineModel. Reaching around this contract, children mutating props, parents grabbing refs into a child's internals, works today and costs a refactor later.

Slots before props, for anything visual

  • A title prop handles a string; a header slot handles the icon, the badge, and the tooltip someone needs next quarter.
  • Scoped slots let a component own behavior, fetching, filtering, keyboard handling, while the consumer owns markup; list and table components almost always want this.
  • If a component has accumulated showIcon, iconPosition, and iconVariant, that is a slot wearing prop clothing.

Habits that scale across a codebase

Type your props and emits with TypeScript, since autocomplete is documentation nobody has to maintain. Give props sensible defaults so the zero-config usage is the common case. Forward attributes to the sensible root element, so class and aria-* land where users expect. And test components through their public contract, render with props, interact, assert on output, rather than poking internals that should stay free to change.

The test of a good component is the call site: if usage reads like a sentence and the weird cases are possible without forking, the design is right.