frontend-conventions
cloudflare/cloudflare-os/.agents/skills/frontend-conventions/SKILL.md
Use for creating, modifying, moving, or reviewing React frontend code anywhere in packages/*, including Workshop pages, gatekeeper management apps, shared UI, components, hooks, forms, interactions, styling, accessibility, and frontend tests.
Skill10k starsChanged 9 days ago
--- name: frontend-conventions description: Use for creating, modifying, moving, or reviewing React frontend code anywhere in packages/*, including Workshop pages, gatekeeper management apps, shared UI, components, hooks, forms, interactions, styling, accessibility, and frontend tests. --- # Frontend Conventions Apply these conventions to the Workshop SPA, gatekeeper management SPAs, and `@gadgets/ui`. Package-level `AGENTS.md` files add product-specific rules but do not replace this guidance. ## Ownership And Organization Organize code by product ownership before implementation type. Feature directories own product behavior and may contain components, hooks, tests, and utilities that change for the same reason. Start directories flat. Do not introduce `components/`, `hooks/`, `helpers/`, or `tests/` subdirectories merely to classify files. Introduce a responsibility-named subsystem directory only when several files form a coherent unit or the flat directory becomes difficult to scan. Use PascalCase filenames for components and camelCase filenames for hooks and non-component modules. Colocate `*.test.ts(x)` files with their subject. Feature organization does not replace the one-component-per-file model. Keep product behavior with its product even when another feature consumes it. Promote code only as high as its ownership requires: - Code shared within one feature belongs at the nearest common feature directory. - Feature-independent code shared across unrelated areas of one app may live in that app's `components/` or `hooks/` directory. - Runtime UI shared by independent frontends belongs in `@gadgets/ui`. - Do not merge components merely because they look similar. Avoid generic prop-heavy abstractions that erase domain behavior. ## Components And Hooks Create a separate component when it owns meaningful state, effects, interactions, accessibility behavior, or reusable responsibility; represents a distinct UI concern; or obscures its parent's main flow. Keep small stateless render helpers private until they develop an independent concern. Extract a hook when it owns a coherent behavior or external synchronization lifecycle, not simply to shorten a file. Keep code together when an extracted child would mostly forward markup or depend on the parent's refs, setters, and synchronization callbacks. Prefer named arrow-function components and hooks. Type props directly rather than using `React.FC`. Give wrappers such as `memo` and `forwardRef` stable DevTools names. ## Component APIs Represent props that are valid only together as an object or discriminated union. A controlled value requires a change callback; otherwise expose an uncontrolled initial value. Do not copy a controlled prop into local state with an Effect. Name callbacks `on<Action>` and pass domain values rather than React setters or browser events. Add `children`, slots, variants, `className`, DOM passthrough, and imperative refs only for current callers, not speculative reuse. Use context for genuinely application-wide values such as authentication, theme, and toasts. Pass instance-specific feature data and actions through props. ## Kumo And Styling Use Kumo components and semantic tokens by default. Check Kumo and `@gadgets/ui` before creating a control or interaction pattern. A shared Gadgets component should compose Kumo behavior, not merely rename or restyle a primitive. Do not add custom color literals, arbitrary Tailwind colors, feature-local token systems, or local replacements for Kumo surfaces, borders, text, status, focus, and interaction tokens unless the user explicitly requests them. Existing legacy colors are not precedent. Tailwind is appropriate for structure, spacing, sizing, positioning, responsive behavior, and typography. Use custom CSS only for technical behavior Kumo and utilities cannot express. Global Kumo token theming is an application-level decision and must not be changed during ordinary feature work. When Kumo is unsuitable, identify the concrete behavioral or accessibility gap before introducing a shared abstraction. ## React Treat Effects as synchronization with external systems, not as derived-state machinery or a way to sequence user interactions. Calculate render data during render, keep state near its owner, prefer a component `key` for identity resets, and use `useSyncExternalStore` for suitable external stores. Effects that fetch or subscribe must clean up stale work and remain correct when restarted. Avoid chains of Effects and do not synchronize two pieces of React state when one can be derived. Do not add `useMemo` or `useCallback` without a concrete identity or performance need. Preserve keyboard behavior, focus management, accessible names, announcements, and mouse/touch/hybrid input parity. RPC stubs must follow the disposal and React state rules in the root `AGENTS.md`. ## Comments Prefer names and types that communicate intent. Comments should explain non-obvious constraints, security or performance reasons, and deliberate departures from conventions. Do not narrate the next line. Remove or update comments when their constraint changes. ## Tests Tests should protect observable behavior, product rules, accessibility, state transitions, races, and failure paths. Do not test React, JavaScript, Kumo, or another framework's own behavior merely for coverage. Avoid assertions coupled only to implementation details or trivial passthrough. Behavior-preserving moves should keep tests unchanged apart from imports. Add focused coverage only when an extraction exposes important previously untested logic.
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

