Compound components
Use small composable primitives when callers need to arrange content or share styling. This convention applies to reusable UI building blocks; a page or domain composition can assemble several elements without turning every element into a new API.
Repository conventions
- Prefer existing
@zoonk/uiprimitives. Put generic patterns inpackages/uiand domain compositions in the owning app or feature. - A presentational primitive normally wraps one semantic element, accepts
childrenandclassName, and exposes the relevant native props. Keep domain data fetching and orchestration in the composition that uses it. - Use flat names such as
MediaCard,MediaCardTitle, andMediaCardDescription; do not introduce namespaced exports such asMediaCard.Title. - Use children for caller-owned content and
classNamefor styling overrides. Avoid bundles of title/description/action props or boolean variants when composition expresses the structure directly. - Name shared primitives by their UI purpose. Domain-specific names remain appropriate for domain compositions.
- Use
data-slotand Tailwind group/has variants for CSS coordination when needed. These attributes are not E2E selectors; preserve semantic elements, labels, and accessible relationships. - Translate fixed copy in the component that owns it. Caller-supplied content is appropriate when it is part of the intended reusable API.
<MediaCard>
<MediaCardContent>
<MediaCardTitle>{title}</MediaCardTitle>
<MediaCardDescription>{description}</MediaCardDescription>
</MediaCardContent>
</MediaCard>
Shared state
Pure visual composition does not need a provider. Use context when siblings must share state/actions or controls outside the main frame need access to them. For those cases, consult Vercel composition patterns, retaining Zoonk's flat naming. Do not add a provider solely to pass static content.
Use E2E coverage for user interactions according to the repository testing guidance; do not add isolated React component tests for these primitives.