New component#
- Searched the starter first — not already covered by a prop on an existing component
- Typed props:
interface Props(ortypefor a union/polymorphic shape, components.props); typed-union variants; defaults in the destructure - Native-attribute passthrough (
extends HTMLAttributes<…>+...rest) if it proxies an element - Slots: default with fallback; named for regions; render-and-inspect for conditional wrappers
- Only semantic tokens / Tailwind utilities — zero hardcoded hex AND zero raw Tailwind neutrals
- Focus ring on every interactive element
- Native semantics first; ARIA only where native falls short; landmark labels; decorative icons
aria-hidden - Keyboard per a11y.keyboard for the pattern; roving tabindex where applicable
- Focus management on open/close/remove; focus not obscured by sticky UI
-
@media (prefers-reduced-motion)+ JSmatchMediaguard for any animation - Animated
<canvas>/rAF: reduced-motion static, paused offscreen/hidden, static fallback, deferred compile (perf.canvas) - Per-behavior init guard (
WeakSetor namespaced flag) +AbortControllerteardown (components.scripting) -
is:global(if used) namespaced under[data-component], with the reason in a comment - Scoped styles use
var(--token)or@reference - Header comment + a
src/content/components/<kebab-name>.mdxshowcase entry -
npm run checkpasses