SPFx React Components: Composition Patterns

SPFx React Components: Composition Patterns

Composition patterns for SPFx components: children-as-API, render props, and light HOCs.

Best practices for composing SPFx components using children, slots, and render props.

Children as API

Use children to let consumers place arbitrary content.

type PanelProps = { title: string; children?: React.ReactNode };
export function Panel({ title, children }: PanelProps) {
	return (
		<section className="panel">
			<h3>{title}</h3>
			<div className="panel-body">{children}</div>
		</section>
	);
}

Named slots via props

Expose specific regions as optional props to avoid prop bloat.

type CardSlotsProps = {
	header?: React.ReactNode;
	footer?: React.ReactNode;
	children?: React.ReactNode;
};
export function CardSlots({ header, footer, children }: CardSlotsProps) {
	return (
		<article className="card">
			{header}
			<div className="card-body">{children}</div>
			{footer}
		</article>
	);
}

Render props

Pass a function to render based on internal state or data.

type DataProviderProps<T> = { url: string; children: (data: T | null) => React.ReactNode };
export function DataProvider<T>({ url, children }: DataProviderProps<T>) {
	const { data, loading } = useCancelableFetch(url);
	if (loading) return <div>Loading…</div>;
	return <>{children(data)}</>;
}

Light HOCs

Prefer small wrappers that add a single capability rather than deep inheritance.

export function withThemeClass<T extends object>(Comp: React.ComponentType<T>) {
	return function Wrapped(props: T) {
		const themeClass = 'theme-default'; // could read from context
		return <div className={themeClass}><Comp {...props} /></div>;
	};
}

Anti‑Patterns

  • Deep component trees with unclear data flow.
  • Overusing HOCs leading to wrapper hell.
  • Passing functions/JSX via props when a simpler children solution suffices.

SPFx composition examples

  • Wrap web part content with WebPartHeader + Panel.
  • Provide data via DataProvider and render presentational component.
  • Keep SPFx context outside presentational components; pass minimal props only.