Review F0 React components against the conventions in packages/react/AGENTS.md. This skill adds review-specific guidance on top of those standards.
Review Workflow
- Read
packages/react/AGENTS.mdfor full component conventions - For components with interactive or animated elements, also load the
a11yskill (.agents/skills/a11y/) for detailed WCAG patterns - Check each item below — flag violations with severity
- Classify issues as blocking (must fix) or suggestion (nice to have)
Blocking Issues
Flag these as blocking — they must be fixed before merge:
TypeScript
anyoras anyusage anywhereimport * as Reactinstead of named imports- Default exports on components
- Circular imports
Component Structure
- Missing
displayNameonforwardRefcomponents - Direct Radix/third-party primitive import (must use
@/ui/wrappers) - New component name missing
F0prefix - New component placed in
experimental/instead ofcomponents/(useexperimentalComponentfrom@/lib/experimental.ts) - Internal components or
internal-types.tsexported publicly - New component not exported in
exports.ts
Testing
- Missing test file for new/changed components
- Test files named
.spec.tsinstead of.test.tsx - Using
renderfrom@testing-library/reactinstead ofzeroRenderfrom@/testing/test-utils.tsx - Using
jest.fn()instead ofvi.fn() - Snapshot testing (use explicit assertions only)
Storybook
- Missing
Snapshotstory withwithSnapshot({})for Chromatic
Security
dangerouslySetInnerHTMLwithout explicit justification
Suggestions (Non-blocking)
Flag these as suggestions:
Code Quality
- Comments describing "what" instead of "why"
- Missing
React.memo/useMemo/useCallbackwhere beneficial - Missing cleanup in
useEffect classNameexposed on public component API (should be a private prop)- Union type props not using const array pattern
Testing
- Using
fireEventwhereuserEventwould be more appropriate - Coverage appears below 80%
- Missing helper functions for repeated multi-step interactions
Accessibility
- Missing
useReducedMotion()check in animated components - Missing
aria-live="polite"on loading/skeleton states - Missing
sr-onlylabel on icon-only buttons - Focusable element missing
focusRing() - Interactive div missing keyboard handler (
onKeyDownfor Enter/Space) ortabIndex={0}+role
i18n
- Hardcoded user-facing strings (should use
useI18n()) - Missing fallback for translation keys
Styling
- CSS modules or CSS-in-JS usage (should use Tailwind)
- CVA imported from
"class-variance-authority"instead of"cva" - Inline
stylefor values expressible as Tailwind classes
Storybook Review
Verify stories follow these F0-specific patterns:
- Meta uses
satisfies Meta<typeof Component>(notas Meta) - Tags include
["autodocs", "stable"]or["autodocs", "experimental"] - ArgTypes for union props reference the component's const array directly
- Union types without const arrays use
table.type.summary - Snapshot story renders all meaningful variants in a flex layout
// Required Snapshot pattern
export const Snapshot: Story = {
parameters: withSnapshot({}),
render: () => (
<div className="flex w-fit flex-col gap-2">
{/* All meaningful variants */}
</div>
),
}
Props Review Checklist
- Names are functional and clear (
only-iconnothide-icon+hide-label) - Union types use exported const arrays:
export const colors = ["a", "b", "c"] as const export type Color = (typeof colors)[number] - Public interfaces are exported, internal types stay in
internal-types.ts - Default prop values set inline during destructuring (not
defaultProps) DataAttributesfrom@/global.typesused fordata-*prop support where needed