Architecture decisions

Style-prop API

motif gives you two ways to author styles — inline style props on a primitive, and a styled() factory that bakes a configuration into a named component. Both are first-class; neither is the one true path.

Updated 4 days agoEdit on GitHubWeb & native

Status

Accepted.

Context

Styling libraries tend to pick a lane. Utility-prop libraries make every style an inline prop; styled-component libraries make every style a named component. Each lane is right for part of a real codebase and wrong for the rest — a one-off layout wants inline props, a button used in ninety places wants to be a component.

Forcing one model means the other use case is always slightly awkward.

Decision

motif ships both APIs, co-designed, with neither marked primary.

  • Style props<Box p="$4" bg="$colors.surface.base" _hover={{ opacity: 0.9 }} />. Styles live at the call site. Right for layout and for anything used once.
  • The styled() factorystyled('button', { base: { … }, variants: { … } }). A configuration baked into a named component, with a typed variants axis. Right for anything reused.

Two supporting decisions fall out of this:

  • Token references are $-prefixed strings. $colors.surface.base, $space.4. The same syntax works in a prop and in a styled() config. The resolver, not a function call, turns the reference into a value.
  • Variants follow the Stitches model — a variants map, compoundVariants for axis interactions, and boolean variants. The variant keys are type-checked against the map.

The two APIs are not separate systems. styled() is configured with the same style-prop schema its output accepts, so a value learned in one place transfers to the other.

Consequences

  • A codebase can mix freely — inline props for the layout, styled() for the component library — without a context switch in mental model.
  • The style-prop schema is large, and it is the same schema in two places. That is deliberate: one schema to learn, one to maintain.
  • Neither API can be deprecated without breaking half of every motif codebase. Committing to both is a permanent commitment.