Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

designComposition Patterns

Let a Primitive Render as Its Child

SHOULD

SHOULD: Give styled primitives an asChild / Slot escape hatch so they can render AS the element they wrap (a Button that is really an <a href>) instead of forcing a fixed tag or nesting interactive elements. Styling stays with the primitive; semantics stay with the child.

Give styled primitives an asChild / Slot escape hatch so a Button can BE a link instead of wrapping one

<Button asChild>
  <a href="/pricing">Pricing</a>
</Button>

Bad

Good

Why it matters

A `<Button>` that only ever renders a `<button>` forces a bad choice the moment you need it to navigate: either fake a link with an onClick (losing href, middle-click, open-in-new-tab, and the right role) or wrap it in an `<a>` and nest two interactive elements, which is invalid and confuses assistive tech. The `asChild` pattern — Radix's Slot — resolves it by merging the primitive's classes, refs, and event handlers onto the single child you pass, so `<Button asChild><a href>` renders one real anchor that looks and behaves like the button.

It keeps styling and semantics in separate hands: the primitive owns the look, the child owns what the element actually IS. This is how shadcn/ui buttons become links, menu items become `<Link>`s, and triggers wrap arbitrary controls without a prop explosion.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.