Rules Hub

Coding Rules Library

← Back to all rules
frontend ruleStack: react
reacttypescriptpropsclean-codecomponents

Prefer ReactNode props over render functions for static content

Define props as ReactNode or JSX.Element instead of render functions or Component types when the content does not rely on the component's internal state.

PR: Feat/FABS-420: Adding fallback for ticker images #246Created: Dec 8, 2025

Bad example

Old codetsx
1interface CardProps {
2 title: string;
3 // Unnecessary render function pattern if no data is passed back
4 renderFooter: () => JSX.Element;
5 // Or restrictive component type
6 Icon: React.ComponentType<{ size: number }>;
7}
8
9export const Card = ({ title, renderFooter, Icon }: CardProps) => (
10 <div className="card">
11 <Icon size={24} />
12 <h1>{title}</h1>
13 <div className="footer">{renderFooter()}</div>
14 </div>
15);
16
17// Usage requires wrapping in anonymous function
18<Card
19 title="Profile"
20 Icon={UserIcon}
21 renderFooter={() => <button>Close</button>}
22/>

Explanation (EN)

Defining props as render functions (`() => JSX.Element`) or `ComponentType` creates unnecessary boilerplate at the usage site when no data needs to be passed from the child to the parent. It forces the consumer to wrap logic in functions or strictly match component interfaces.

Objašnjenje (HR)

Definiranje propova kao funkcija za renderiranje (`() => JSX.Element`) ili `ComponentType` stvara nepotreban 'boilerplate' pri korištenju kada nije potrebno prosljeđivati podatke od djeteta roditelju. To prisiljava potrošača da omata logiku u funkcije ili strogo prati sučelja komponenti.

Good example

New codetsx
1import { ReactNode } from 'react';
2
3interface CardProps {
4 title: string;
5 // Flexible: accepts any rendered element, string, or null
6 footer?: ReactNode;
7 icon?: ReactNode;
8}
9
10export const Card = ({ title, footer, icon }: CardProps) => (
11 <div className="card">
12 {icon}
13 <h1>{title}</h1>
14 {footer && <div className="footer">{footer}</div>}
15 </div>
16);
17
18// Usage is direct, cleaner, and more flexible
19<Card
20 title="Profile"
21 icon={<UserIcon size={24} />}
22 footer={<button>Close</button>}
23/>

Explanation (EN)

Using `ReactNode` (or `JSX.Element`) allows the consumer to pass anything that React can render directly (elements, strings, null). It simplifies the usage syntax by removing the need for arrow functions and allows pre-configured components to be passed easily.

Objašnjenje (HR)

Korištenje `ReactNode` (ili `JSX.Element`) omogućuje potrošaču da izravno proslijedi bilo što što React može renderirati (elemente, stringove, null). To pojednostavljuje sintaksu uklanjanjem potrebe za 'arrow' funkcijama i omogućuje lako prosljeđivanje unaprijed konfiguriranih komponenti.

Notes (EN)

Only use render props (functions) if you need to pass internal state from the child component back to the injected content (e.g., renderItem={(item) => ...}).

Bilješke (HR)

Koristite 'render props' (funkcije) samo ako trebate proslijediti interno stanje iz djeteta u ubrizgani sadržaj (npr. renderItem={(item) => ...}).