React Essentials — Components, JSX, Props, State & MoreEntry 2 of 11

children vs Attribute Props and Component Composition

children is the special prop holding whatever JSX is placed between a component's opening and closing tags. Attribute props are values passed as named attributes.

Notes

Composition means building complex UIs by nesting simple components. A wrapper component doesn't need to know what it wraps; it renders children wherever the content should appear.

The same TabButton can receive its label either way:

  • Using children: <TabButton>Components</TabButton>. Best for components that take a single piece of renderable content. It's closer to normal HTML usage and is especially convenient when passing JSX as a value to another component.
  • Using attributes: <TabButton label="Components" />. Best when a component needs multiple smaller pieces of information. The trade-off is extra work: each piece needs its own prop.

Ultimately, the choice comes down to the use case and personal preference.

What / Why / When

What

Content passed between tags instead of as a named attribute.

Why

It produces generic wrappers (cards, modals, layouts) that work with any content.

When

The component defines the frame and the parent supplies the contents.

Use case

A Card or Modal wrapper used across the whole app.

Code compare

React
import type { ReactNode } from "react";​// Using childrenexport function TabButton({ children }: { children: ReactNode }) {  return <button>{children}</button>;}​// Using an attribute propexport function TabButtonWithLabel({ label }: { label: string }) {  return <button>{label}</button>;}
React
<TabButton>Components</TabButton><TabButtonWithLabel label="Components" />

A generic wrapper:

React
import type { ReactNode } from "react";​export function Card({ children }: { children: ReactNode }) {  return <div className="card">{children}</div>;}​<Card>  <h2>Title</h2>  <p>Any JSX can go here.</p></Card>;
Angular
import { Component, input } from "@angular/core";​// children → ng-content@Component({  selector: "app-tab-button",  template: `<button><ng-content /></button>`,})export class TabButtonComponent {}​// attribute prop → input()@Component({  selector: "app-tab-button-label",  template: `<button>{{ label() }}</button>`,})export class TabButtonLabelComponent {  label = input.required<string>();}
Angular
<app-tab-button>Components</app-tab-button> <app-tab-button-label label="Components" />

Differences and gotchas

  • children is a value. You can render it conditionally, render it twice, or inspect it. <ng-content> projects content exactly once.
  • Projected content in Angular is created by the parent even if the child wraps <ng-content> in an @if. For truly lazy or repeated content, pass an <ng-template> instead.

Quick reference

ReactAngular
children prop<ng-content />
Attribute propsinput()