RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/AGENTS.md/itxSaaad/medlens-plus-app

AGENTS.md

.claude/skills/web-frontend/references/composition-patterns/AGENTS.md
AGENTS.md

Quality

57/100

Scores the file, not the repository.

Length

2,495 words

16 headings · 28 code blocks

Repository

0

— · pushed 1 days ago

Last changed

3 days ago

First indexed 3 days ago.
itxSaaad/medlens-plus-app/.claude/skills/web-frontend/references/composition-patterns/AGENTS.mdRawGitHub
1# React Composition Patterns
2 
3**Version 1.0.0**
4Engineering
5January 2026
6 
7> **Note:**
8> This document is mainly for agents and LLMs to follow when maintaining,
9> generating, or refactoring React codebases using composition. Humans
10> may also find it useful, but guidance here is optimized for automation
11> and consistency by AI-assisted workflows.
12 
13---
14 
15## Abstract
16 
17Composition patterns for building flexible, maintainable React components. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. These patterns make codebases easier for both humans and AI agents to work with as they scale.
18 
19---
20 
21## Table of Contents
22 
231. [Component Architecture](#1-component-architecture) — **HIGH**
24 - 1.1 [Avoid Boolean Prop Proliferation](#11-avoid-boolean-prop-proliferation)
25 - 1.2 [Use Compound Components](#12-use-compound-components)
262. [State Management](#2-state-management) — **MEDIUM**
27 - 2.1 [Decouple State Management from UI](#21-decouple-state-management-from-ui)
28 - 2.2 [Define Generic Context Interfaces for Dependency Injection](#22-define-generic-context-interfaces-for-dependency-injection)
29 - 2.3 [Lift State into Provider Components](#23-lift-state-into-provider-components)
303. [Implementation Patterns](#3-implementation-patterns) — **MEDIUM**
31 - 3.1 [Create Explicit Component Variants](#31-create-explicit-component-variants)
32 - 3.2 [Prefer Composing Children Over Render Props](#32-prefer-composing-children-over-render-props)
334. [React 19 APIs](#4-react-19-apis) — **MEDIUM**
34 - 4.1 [React 19 API Changes](#41-react-19-api-changes)
35 
36---
37 
38## 1. Component Architecture
39 
40**Impact: HIGH**
41 
42Fundamental patterns for structuring components to avoid prop
43proliferation and enable flexible composition.
44 
45### 1.1 Avoid Boolean Prop Proliferation
46 
47**Impact: CRITICAL (prevents unmaintainable component variants)**
48 
49Don't add boolean props like `isThread`, `isEditing`, `isDMThread` to customize
50 
51component behavior. Each boolean doubles possible states and creates
52 
53unmaintainable conditional logic. Use composition instead.
54 
55**Incorrect: boolean props create exponential complexity**
56 
57```tsx
58function Composer({
59 onSubmit,
60 isThread,
61 channelId,
62 isDMThread,
63 dmId,
64 isEditing,
65 isForwarding,
66}: Props) {
67 return (
68 <form>
69 <Header />
70 <Input />
71 {isDMThread ? (
72 <AlsoSendToDMField id={dmId} />
73 ) : isThread ? (
74 <AlsoSendToChannelField id={channelId} />
75 ) : null}
76 {isEditing ? <EditActions /> : isForwarding ? <ForwardActions /> : <DefaultActions />}
77 <Footer onSubmit={onSubmit} />
78 </form>
79 );
80}
81```
82 
83**Correct: composition eliminates conditionals**
84 
85```tsx
86// Channel composer
87function ChannelComposer() {
88 return (
89 <Composer.Frame>
90 <Composer.Header />
91 <Composer.Input />
92 <Composer.Footer>
93 <Composer.Attachments />
94 <Composer.Formatting />
95 <Composer.Emojis />
96 <Composer.Submit />
97 </Composer.Footer>
98 </Composer.Frame>
99 );
100}
101 
102// Thread composer - adds "also send to channel" field
103function ThreadComposer({ channelId }: { channelId: string }) {
104 return (
105 <Composer.Frame>
106 <Composer.Header />
107 <Composer.Input />
108 <AlsoSendToChannelField id={channelId} />
109 <Composer.Footer>
110 <Composer.Formatting />
111 <Composer.Emojis />
112 <Composer.Submit />
113 </Composer.Footer>
114 </Composer.Frame>
115 );
116}
117 
118// Edit composer - different footer actions
119function EditComposer() {
120 return (
121 <Composer.Frame>
122 <Composer.Input />
123 <Composer.Footer>
124 <Composer.Formatting />
125 <Composer.Emojis />
126 <Composer.CancelEdit />
127 <Composer.SaveEdit />
128 </Composer.Footer>
129 </Composer.Frame>
130 );
131}
132```
133 
134Each variant is explicit about what it renders. We can share internals without
135 
136sharing a single monolithic parent.
137 
138### 1.2 Use Compound Components
139 
140**Impact: HIGH (enables flexible composition without prop drilling)**
141 
142Structure complex components as compound components with a shared context. Each
143 
144subcomponent accesses shared state via context, not props. Consumers compose the
145 
146pieces they need.
147 
148**Incorrect: monolithic component with render props**
149 
150```tsx
151function Composer({
152 renderHeader,
153 renderFooter,
154 renderActions,
155 showAttachments,
156 showFormatting,
157 showEmojis,
158}: Props) {
159 return (
160 <form>
161 {renderHeader?.()}
162 <Input />
163 {showAttachments && <Attachments />}
164 {renderFooter ? (
165 renderFooter()
166 ) : (
167 <Footer>
168 {showFormatting && <Formatting />}
169 {showEmojis && <Emojis />}
170 {renderActions?.()}
171 </Footer>
172 )}
173 </form>
174 );
175}
176```
177 
178**Correct: compound components with shared context**
179 
180```tsx
181const ComposerContext = createContext<ComposerContextValue | null>(null);
182 
183function ComposerProvider({ children, state, actions, meta }: ProviderProps) {
184 return <ComposerContext value={{ state, actions, meta }}>{children}</ComposerContext>;
185}
186 
187function ComposerFrame({ children }: { children: React.ReactNode }) {
188 return <form>{children}</form>;
189}
190 
191function ComposerInput() {
192 const {
193 state,
194 actions: { update },
195 meta: { inputRef },
196 } = use(ComposerContext);
197 return (
198 <TextInput
199 ref={inputRef}
200 value={state.input}
201 onChangeText={(text) => update((s) => ({ ...s, input: text }))}
202 />
203 );
204}
205 
206function ComposerSubmit() {
207 const {
208 actions: { submit },
209 } = use(ComposerContext);
210 return <Button onPress={submit}>Send</Button>;
211}
212 
213// Export as compound component
214const Composer = {
215 Provider: ComposerProvider,
216 Frame: ComposerFrame,
217 Input: ComposerInput,
218 Submit: ComposerSubmit,
219 Header: ComposerHeader,
220 Footer: ComposerFooter,
221 Attachments: ComposerAttachments,
222 Formatting: ComposerFormatting,
223 Emojis: ComposerEmojis,
224};
225```
226 
227**Usage:**
228 
229```tsx
230<Composer.Provider state={state} actions={actions} meta={meta}>
231 <Composer.Frame>
232 <Composer.Header />
233 <Composer.Input />
234 <Composer.Footer>
235 <Composer.Formatting />
236 <Composer.Submit />
237 </Composer.Footer>
238 </Composer.Frame>
239</Composer.Provider>
240```
241 
242Consumers explicitly compose exactly what they need. No hidden conditionals. And the state, actions and meta are dependency-injected by a parent provider, allowing multiple usages of the same component structure.
243 
244---
245 
246## 2. State Management
247 
248**Impact: MEDIUM**
249 
250Patterns for lifting state and managing shared context across
251composed components.
252 
253### 2.1 Decouple State Management from UI
254 
255**Impact: MEDIUM (enables swapping state implementations without changing UI)**
256 
257The provider component should be the only place that knows how state is managed.
258 
259UI components consume the context interface—they don't know if state comes from
260 
261useState, Zustand, or a server sync.
262 
263**Incorrect: UI coupled to state implementation**
264 
265```tsx
266function ChannelComposer({ channelId }: { channelId: string }) {
267 // UI component knows about global state implementation
268 const state = useGlobalChannelState(channelId);
269 const { submit, updateInput } = useChannelSync(channelId);
270 
271 return (
272 <Composer.Frame>
273 <Composer.Input value={state.input} onChange={(text) => sync.updateInput(text)} />
274 <Composer.Submit onPress={() => sync.submit()} />
275 </Composer.Frame>
276 );
277}
278```
279 
280**Correct: state management isolated in provider**
281 
282```tsx
283// Provider handles all state management details
284function ChannelProvider({
285 channelId,
286 children,
287}: {
288 channelId: string;
289 children: React.ReactNode;
290}) {
291 const { state, update, submit } = useGlobalChannel(channelId);
292 const inputRef = useRef(null);
293 
294 return (
295 <Composer.Provider state={state} actions={{ update, submit }} meta={{ inputRef }}>
296 {children}
297 </Composer.Provider>
298 );
299}
300 
301// UI component only knows about the context interface
302function ChannelComposer() {
303 return (
304 <Composer.Frame>
305 <Composer.Header />
306 <Composer.Input />
307 <Composer.Footer>
308 <Composer.Submit />
309 </Composer.Footer>
310 </Composer.Frame>
311 );
312}
313 
314// Usage
315function Channel({ channelId }: { channelId: string }) {
316 return (
317 <ChannelProvider channelId={channelId}>
318 <ChannelComposer />
319 </ChannelProvider>
320 );
321}
322```
323 
324**Different providers, same UI:**
325 
326```tsx
327// Local state for ephemeral forms
328function ForwardMessageProvider({ children }) {
329 const [state, setState] = useState(initialState);
330 const forwardMessage = useForwardMessage();
331 
332 return (
333 <Composer.Provider state={state} actions={{ update: setState, submit: forwardMessage }}>
334 {children}
335 </Composer.Provider>
336 );
337}
338 
339// Global synced state for channels
340function ChannelProvider({ channelId, children }) {
341 const { state, update, submit } = useGlobalChannel(channelId);
342 
343 return (
344 <Composer.Provider state={state} actions={{ update, submit }}>
345 {children}
346 </Composer.Provider>
347 );
348}
349```
350 
351The same `Composer.Input` component works with both providers because it only
352 
353depends on the context interface, not the implementation.
354 
355### 2.2 Define Generic Context Interfaces for Dependency Injection
356 
357**Impact: HIGH (enables dependency-injectable state across use-cases)**
358 
359Define a **generic interface** for your component context with three parts:
360 
361`state`, `actions`, and `meta`. This interface is a contract that any provider
362 
363can implement—enabling the same UI components to work with completely different
364 
365state implementations.
366 
367**Core principle:** Lift state, compose internals, make state
368 
369dependency-injectable.
370 
371**Incorrect: UI coupled to specific state implementation**
372 
373```tsx
374function ComposerInput() {
375 // Tightly coupled to a specific hook
376 const { input, setInput } = useChannelComposerState();
377 return <TextInput value={input} onChangeText={setInput} />;
378}
379```
380 
381**Correct: generic interface enables dependency injection**
382 
383```tsx
384// Define a GENERIC interface that any provider can implement
385interface ComposerState {
386 input: string;
387 attachments: Attachment[];
388 isSubmitting: boolean;
389}
390 
391interface ComposerActions {
392 update: (updater: (state: ComposerState) => ComposerState) => void;
393 submit: () => void;
394}
395 
396interface ComposerMeta {
397 inputRef: React.RefObject<TextInput>;
398}
399 
400interface ComposerContextValue {
401 state: ComposerState;
402 actions: ComposerActions;
403 meta: ComposerMeta;
404}
405 
406const ComposerContext = createContext<ComposerContextValue | null>(null);
407```
408 
409**UI components consume the interface, not the implementation:**
410 
411```tsx
412function ComposerInput() {
413 const {
414 state,
415 actions: { update },
416 meta,
417 } = use(ComposerContext);
418 
419 // This component works with ANY provider that implements the interface
420 return (
421 <TextInput
422 ref={meta.inputRef}
423 value={state.input}
424 onChangeText={(text) => update((s) => ({ ...s, input: text }))}
425 />
426 );
427}
428```
429 
430**Different providers implement the same interface:**
431 
432```tsx
433// Provider A: Local state for ephemeral forms
434function ForwardMessageProvider({ children }: { children: React.ReactNode }) {
435 const [state, setState] = useState(initialState);
436 const inputRef = useRef(null);
437 const submit = useForwardMessage();
438 
439 return (
440 <ComposerContext
441 value={{
442 state,
443 actions: { update: setState, submit },
444 meta: { inputRef },
445 }}
446 >
447 {children}
448 </ComposerContext>
449 );
450}
451 
452// Provider B: Global synced state for channels
453function ChannelProvider({ channelId, children }: Props) {
454 const { state, update, submit } = useGlobalChannel(channelId);
455 const inputRef = useRef(null);
456 
457 return (
458 <ComposerContext
459 value={{
460 state,
461 actions: { update, submit },
462 meta: { inputRef },
463 }}
464 >
465 {children}
466 </ComposerContext>
467 );
468}
469```
470 
471**The same composed UI works with both:**
472 
473```tsx
474// Works with ForwardMessageProvider (local state)
475<ForwardMessageProvider>
476 <Composer.Frame>
477 <Composer.Input />
478 <Composer.Submit />
479 </Composer.Frame>
480</ForwardMessageProvider>
481 
482// Works with ChannelProvider (global synced state)
483<ChannelProvider channelId="abc">
484 <Composer.Frame>
485 <Composer.Input />
486 <Composer.Submit />
487 </Composer.Frame>
488</ChannelProvider>
489```
490 
491**Custom UI outside the component can access state and actions:**
492 
493```tsx
494function ForwardMessageDialog() {
495 return (
496 <ForwardMessageProvider>
497 <Dialog>
498 {/* The composer UI */}
499 <Composer.Frame>
500 <Composer.Input placeholder="Add a message, if you'd like." />
501 <Composer.Footer>
502 <Composer.Formatting />
503 <Composer.Emojis />
504 </Composer.Footer>
505 </Composer.Frame>
506 
507 {/* Custom UI OUTSIDE the composer, but INSIDE the provider */}
508 <MessagePreview />
509 
510 {/* Actions at the bottom of the dialog */}
511 <DialogActions>
512 <CancelButton />
513 <ForwardButton />
514 </DialogActions>
515 </Dialog>
516 </ForwardMessageProvider>
517 );
518}
519 
520// This button lives OUTSIDE Composer.Frame but can still submit based on its context!
521function ForwardButton() {
522 const {
523 actions: { submit },
524 } = use(ComposerContext);
525 return <Button onPress={submit}>Forward</Button>;
526}
527 
528// This preview lives OUTSIDE Composer.Frame but can read composer's state!
529function MessagePreview() {
530 const { state } = use(ComposerContext);
531 return <Preview message={state.input} attachments={state.attachments} />;
532}
533```
534 
535The provider boundary is what matters—not the visual nesting. Components that
536 
537need shared state don't have to be inside the `Composer.Frame`. They just need
538 
539to be within the provider.
540 
541The `ForwardButton` and `MessagePreview` are not visually inside the composer
542 
543box, but they can still access its state and actions. This is the power of
544 
545lifting state into providers.
546 
547The UI is reusable bits you compose together. The state is dependency-injected
548 
549by the provider. Swap the provider, keep the UI.
550 
551### 2.3 Lift State into Provider Components
552 
553**Impact: HIGH (enables state sharing outside component boundaries)**
554 
555Move state management into dedicated provider components. This allows sibling
556 
557components outside the main UI to access and modify state without prop drilling
558 
559or awkward refs.
560 
561**Incorrect: state trapped inside component**
562 
563```tsx
564function ForwardMessageComposer() {
565 const [state, setState] = useState(initialState);
566 const forwardMessage = useForwardMessage();
567 
568 return (
569 <Composer.Frame>
570 <Composer.Input />
571 <Composer.Footer />
572 </Composer.Frame>
573 );
574}
575 
576// Problem: How does this button access composer state?
577function ForwardMessageDialog() {
578 return (
579 <Dialog>
580 <ForwardMessageComposer />
581 <MessagePreview /> {/* Needs composer state */}
582 <DialogActions>
583 <CancelButton />
584 <ForwardButton /> {/* Needs to call submit */}
585 </DialogActions>
586 </Dialog>
587 );
588}
589```
590 
591**Incorrect: useEffect to sync state up**
592 
593```tsx
594function ForwardMessageDialog() {
595 const [input, setInput] = useState("");
596 return (
597 <Dialog>
598 <ForwardMessageComposer onInputChange={setInput} />
599 <MessagePreview input={input} />
600 </Dialog>
601 );
602}
603 
604function ForwardMessageComposer({ onInputChange }) {
605 const [state, setState] = useState(initialState);
606 useEffect(() => {
607 onInputChange(state.input); // Sync on every change 😬
608 }, [state.input]);
609}
610```
611 
612**Incorrect: reading state from ref on submit**
613 
614```tsx
615function ForwardMessageDialog() {
616 const stateRef = useRef(null);
617 return (
618 <Dialog>
619 <ForwardMessageComposer stateRef={stateRef} />
620 <ForwardButton onPress={() => submit(stateRef.current)} />
621 </Dialog>
622 );
623}
624```
625 
626**Correct: state lifted to provider**
627 
628```tsx
629function ForwardMessageProvider({ children }: { children: React.ReactNode }) {
630 const [state, setState] = useState(initialState);
631 const forwardMessage = useForwardMessage();
632 const inputRef = useRef(null);
633 
634 return (
635 <Composer.Provider
636 state={state}
637 actions={{ update: setState, submit: forwardMessage }}
638 meta={{ inputRef }}
639 >
640 {children}
641 </Composer.Provider>
642 );
643}
644 
645function ForwardMessageDialog() {
646 return (
647 <ForwardMessageProvider>
648 <Dialog>
649 <ForwardMessageComposer />
650 <MessagePreview /> {/* Custom components can access state and actions */}
651 <DialogActions>
652 <CancelButton />
653 <ForwardButton /> {/* Custom components can access state and actions */}
654 </DialogActions>
655 </Dialog>
656 </ForwardMessageProvider>
657 );
658}
659 
660function ForwardButton() {
661 const { actions } = use(Composer.Context);
662 return <Button onPress={actions.submit}>Forward</Button>;
663}
664```
665 
666The ForwardButton lives outside the Composer.Frame but still has access to the
667 
668submit action because it's within the provider. Even though it's a one-off
669 
670component, it can still access the composer's state and actions from outside the
671 
672UI itself.
673 
674**Key insight:** Components that need shared state don't have to be visually
675 
676nested inside each other—they just need to be within the same provider.
677 
678---
679 
680## 3. Implementation Patterns
681 
682**Impact: MEDIUM**
683 
684Specific techniques for implementing compound components and
685context providers.
686 
687### 3.1 Create Explicit Component Variants
688 
689**Impact: MEDIUM (self-documenting code, no hidden conditionals)**
690 
691Instead of one component with many boolean props, create explicit variant
692 
693components. Each variant composes the pieces it needs. The code documents
694 
695itself.
696 
697**Incorrect: one component, many modes**
698 
699```tsx
700// What does this component actually render?
701<Composer isThread isEditing={false} channelId="abc" showAttachments showFormatting={false} />
702```
703 
704**Correct: explicit variants**
705 
706```tsx
707// Immediately clear what this renders
708<ThreadComposer channelId="abc" />
709 
710// Or
711<EditMessageComposer messageId="xyz" />
712 
713// Or
714<ForwardMessageComposer messageId="123" />
715```
716 
717Each implementation is unique, explicit and self-contained. Yet they can each
718 
719use shared parts.
720 
721**Implementation:**
722 
723```tsx
724function ThreadComposer({ channelId }: { channelId: string }) {
725 return (
726 <ThreadProvider channelId={channelId}>
727 <Composer.Frame>
728 <Composer.Input />
729 <AlsoSendToChannelField channelId={channelId} />
730 <Composer.Footer>
731 <Composer.Formatting />
732 <Composer.Emojis />
733 <Composer.Submit />
734 </Composer.Footer>
735 </Composer.Frame>
736 </ThreadProvider>
737 );
738}
739 
740function EditMessageComposer({ messageId }: { messageId: string }) {
741 return (
742 <EditMessageProvider messageId={messageId}>
743 <Composer.Frame>
744 <Composer.Input />
745 <Composer.Footer>
746 <Composer.Formatting />
747 <Composer.Emojis />
748 <Composer.CancelEdit />
749 <Composer.SaveEdit />
750 </Composer.Footer>
751 </Composer.Frame>
752 </EditMessageProvider>
753 );
754}
755 
756function ForwardMessageComposer({ messageId }: { messageId: string }) {
757 return (
758 <ForwardMessageProvider messageId={messageId}>
759 <Composer.Frame>
760 <Composer.Input placeholder="Add a message, if you'd like." />
761 <Composer.Footer>
762 <Composer.Formatting />
763 <Composer.Emojis />
764 <Composer.Mentions />
765 </Composer.Footer>
766 </Composer.Frame>
767 </ForwardMessageProvider>
768 );
769}
770```
771 
772Each variant is explicit about:
773 
774- What provider/state it uses
775 
776- What UI elements it includes
777 
778- What actions are available
779 
780No boolean prop combinations to reason about. No impossible states.
781 
782### 3.2 Prefer Composing Children Over Render Props
783 
784**Impact: MEDIUM (cleaner composition, better readability)**
785 
786Use `children` for composition instead of `renderX` props. Children are more
787 
788readable, compose naturally, and don't require understanding callback
789 
790signatures.
791 
792**Incorrect: render props**
793 
794```tsx
795function Composer({
796 renderHeader,
797 renderFooter,
798 renderActions,
799}: {
800 renderHeader?: () => React.ReactNode;
801 renderFooter?: () => React.ReactNode;
802 renderActions?: () => React.ReactNode;
803}) {
804 return (
805 <form>
806 {renderHeader?.()}
807 <Input />
808 {renderFooter ? renderFooter() : <DefaultFooter />}
809 {renderActions?.()}
810 </form>
811 );
812}
813 
814// Usage is awkward and inflexible
815return (
816 <Composer
817 renderHeader={() => <CustomHeader />}
818 renderFooter={() => (
819 <>
820 <Formatting />
821 <Emojis />
822 </>
823 )}
824 renderActions={() => <SubmitButton />}
825 />
826);
827```
828 
829**Correct: compound components with children**
830 
831```tsx
832function ComposerFrame({ children }: { children: React.ReactNode }) {
833 return <form>{children}</form>;
834}
835 
836function ComposerFooter({ children }: { children: React.ReactNode }) {
837 return <footer className="flex">{children}</footer>;
838}
839 
840// Usage is flexible
841return (
842 <Composer.Frame>
843 <CustomHeader />
844 <Composer.Input />
845 <Composer.Footer>
846 <Composer.Formatting />
847 <Composer.Emojis />
848 <SubmitButton />
849 </Composer.Footer>
850 </Composer.Frame>
851);
852```
853 
854**When render props are appropriate:**
855 
856```tsx
857// Render props work well when you need to pass data back
858<List data={items} renderItem={({ item, index }) => <Item item={item} index={index} />} />
859```
860 
861Use render props when the parent needs to provide data or state to the child.
862 
863Use children when composing static structure.
864 
865---
866 
867## 4. React 19 APIs
868 
869**Impact: MEDIUM**
870 
871React 19+ only. Don't use `forwardRef`; use `use()` instead of `useContext()`.
872 
873### 4.1 React 19 API Changes
874 
875**Impact: MEDIUM (cleaner component definitions and context usage)**
876 
877> **⚠️ React 19+ only.** Skip this if you're on React 18 or earlier.
878 
879In React 19, `ref` is now a regular prop (no `forwardRef` wrapper needed), and `use()` replaces `useContext()`.
880 
881**Incorrect: forwardRef in React 19**
882 
883```tsx
884const ComposerInput = forwardRef<TextInput, Props>((props, ref) => {
885 return <TextInput ref={ref} {...props} />;
886});
887```
888 
889**Correct: ref as a regular prop**
890 
891```tsx
892function ComposerInput({ ref, ...props }: Props & { ref?: React.Ref<TextInput> }) {
893 return <TextInput ref={ref} {...props} />;
894}
895```
896 
897**Incorrect: useContext in React 19**
898 
899```tsx
900const value = useContext(MyContext);
901```
902 
903**Correct: use instead of useContext**
904 
905```tsx
906const value = use(MyContext);
907```
908 
909`use()` can also be called conditionally, unlike `useContext()`.
910 
911---
912 
913## References
914 
9151. [https://react.dev](https://react.dev)
9162. [https://react.dev/learn/passing-data-deeply-with-context](https://react.dev/learn/passing-data-deeply-with-context)
9173. [https://react.dev/reference/react/use](https://react.dev/reference/react/use)
918 

Sections

  • React Composition Patterns
  • Abstract
  • Table of Contents
  • 1. Component Architecture
  • 1.1 Avoid Boolean Prop Proliferation
  • 1.2 Use Compound Components
  • 2. State Management
  • 2.1 Decouple State Management from UI
  • 2.2 Define Generic Context Interfaces for Dependency Injection
  • 2.3 Lift State into Provider Components
  • 3. Implementation Patterns
  • 3.1 Create Explicit Component Variants
  • 3.2 Prefer Composing Children Over Render Props
  • 4. React 19 APIs
  • 4.1 React 19 API Changes
  • References

What it covers

code-styleapiuido-not

Stack — with the evidence

typescript

(1.00)

turborepo

(1.00)

eslint

(1.00)

node

(0.70)

react

(0.70)

nextjs

(0.70)

fastapi

(0.70)

react-native

(0.70)

expo

(0.70)

postgres

(0.70)

redis

(0.70)

tailwind

(0.70)

vitest

(0.70)

pytest

(0.70)

ruff

(0.70)

javascript

(0.60)

monorepo

(0.60)

pnpm

(0.60)

github-actions

(0.60)

python

(0.50)

Format

AGENTS.md

A plain-markdown README for coding agents, deliberately unopinionated: no frontmatter, no globs, no vendor keys. That minimalism is why it became the one file a dozen different agents will read, and why it carries the least per-file targeting power of any format here.

What the corpus says about it

Repository

Owner
itxSaaad
Language
—
License
—
Archived
no

All configs in this repo

Also in itxSaaad/medlens-plus-app

Diff this repo’s formats

One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
itxSaaad/medlens-plus-app.cursor/rules/testing.mdc · 0Cursor rulestypescriptturborepo+18testtesting-strategyapimonorepo29/1003 days ago
itxSaaad/medlens-plus-app.claude/skills/web-frontend/references/react-best-practices/AGENTS.md · 0AGENTS.mdtypescriptturborepo+18buildstyletypessecurity+665/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/agent-discipline.mdc · 0Cursor rulestypescriptturborepo+18teststyleagent-behaviour53/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/devops-ci.mdc · 0Cursor rulestypescriptturborepo+18securitydo-not23/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/engineering-standards.mdc · 0Cursor rulestypescriptturborepo+18test35/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/fastapi-backend.mdc · 0Cursor rulestypescriptturborepo+18testlint-formatstyle66/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/frontend-quality.mdc · 0Cursor rulestypescriptturborepo+18securityui33/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/github-delivery.mdc · 0Cursor rulestypescriptturborepo+18git16/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/graphify.mdc · 0Cursor rulestypescriptturborepo+18do-not45/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/langgraph-ai-workflows.mdc · 0Cursor rulestypescriptturborepo+18do-not32/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/medical-safety.mdc · 0Cursor rulestypescriptturborepo+18do-not23/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/nextjs-frontend.mdc · 0Cursor rulestypescriptturborepo+18teststylearch80/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/pr-quality-gate.mdc · 0Cursor rulestypescriptturborepo+18testgit43/1003 days ago
itxSaaad/medlens-plus-app.cursor/rules/technical-seo.mdc · 0Cursor rulestypescriptturborepo+18no sections24/1003 days ago
itxSaaad/medlens-plus-app.cursor/skills/web-frontend/references/composition-patterns/AGENTS.md · 0AGENTS.mdtypescriptturborepo+18styleapiuido-not45/1003 days ago
itxSaaad/medlens-plus-app.cursor/skills/web-frontend/references/react-best-practices/AGENTS.md · 0AGENTS.mdtypescriptturborepo+18buildstyletypessecurity+665/1003 days ago
itxSaaad/medlens-plus-app.github/copilot-instructions.md · 0Copilot instructionstypescriptturborepo+18testgitdo-notagent-behaviour+170/1003 days ago
itxSaaad/medlens-plus-appAGENTS.md · 0AGENTS.mdtypescriptturborepo+18gitdo-notagent-behaviour59/1003 days ago
itxSaaad/medlens-plus-appapps/mobile/CLAUDE.md · 0CLAUDE.mdtypescriptreact-native+18stylearchmonorepoagent-behaviour86/1003 days ago
itxSaaad/medlens-plus-appCLAUDE.md · 0CLAUDE.mdtypescriptturborepo+18testgitmonorepodo-not+176/1003 days ago
Diff against .cursor/rules/testing.mdc Diff against .claude/skills/web-frontend/references/react-best-practices/AGENTS.md Diff against .cursor/rules/agent-discipline.mdc Diff against .cursor/rules/devops-ci.mdc Diff against .cursor/rules/engineering-standards.mdc Diff against .cursor/rules/fastapi-backend.mdc Diff against .cursor/rules/frontend-quality.mdc Diff against .cursor/rules/github-delivery.mdc Diff against .cursor/rules/graphify.mdc Diff against .cursor/rules/langgraph-ai-workflows.mdc Diff against .cursor/rules/medical-safety.mdc Diff against .cursor/rules/nextjs-frontend.mdc Diff against .cursor/rules/pr-quality-gate.mdc Diff against .cursor/rules/technical-seo.mdc Diff against .cursor/skills/web-frontend/references/composition-patterns/AGENTS.md Diff against .cursor/skills/web-frontend/references/react-best-practices/AGENTS.md Diff against .github/copilot-instructions.md Diff against AGENTS.md Diff against apps/mobile/CLAUDE.md Diff against CLAUDE.md

Similar configs

Same format, overlapping stack, ranked by quality.

Same format, overlapping stack, ranked by quality
RepositoryFormatStackCoversScoreChanged
mui/material-uiAGENTS.md · 99kAGENTS.mdtypescriptjavascript+13setupbuildtestlint-format+9100/1003 days ago
TryGhost/Ghoste2e/AGENTS.md · 55kAGENTS.mdtypescriptjavascript+12setupteststylearch+2100/1003 days ago
SkeneTechnologies/skene-cookbookAGENTS.md · 51AGENTS.mdpythoneslint+4setupbuildtestlint-format+7100/1002 days ago
duckduckgo/content-scope-scriptsspecial-pages/AGENTS.md · 70AGENTS.mdtypescriptjavascript+5buildteststylearch+3100/1003 days ago
n8n-io/n8npackages/@n8n/agents/AGENTS.md · 199kAGENTS.mdtypescriptlangchain+16buildteststylearch+3100/1003 days ago
aaif-goose/gooseAGENTS.md · 52kAGENTS.mdrusttypescript+2setupbuildtestlint-format+6100/1003 days ago
trick77/agents-md-syncAGENTS.md · 2AGENTS.mdtypescriptnode+4setupbuildteststyle+5100/1003 days ago
code-yeongyu/oh-my-openagentpackages/web/AGENTS.md · 67kAGENTS.mdtypescriptbun+10setupbuildtestlint-format+6100/1002 days ago
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack