Skip to main content

Children

Utilities for manipulating and transforming the children prop. This API is mostly unnecessary in Preact but provided for React compatibility.

API

const Children: {
  map<T, R>(
    children: T | T[],
    fn: (child: T, i: number) => R,
    context?: any
  ): R[];
  
  forEach<T>(
    children: T | T[],
    fn: (child: T, i: number) => void,
    context?: any
  ): void;
  
  count(children: ComponentChildren): number;
  
  only(children: ComponentChildren): ComponentChild;
  
  toArray(children: ComponentChildren): VNode<{}>[];
}

Methods

Children.map

Transform each child and return a new array.
import { Children } from 'preact/compat';

function AddProps({ children }) {
  return (
    <div>
      {Children.map(children, (child, index) => (
        // Clone each child and add a className
        <child.type {...child.props} className="mapped-child" key={index} />
      ))}
    </div>
  );
}

// Usage
<AddProps>
  <div>First</div>
  <div>Second</div>
  <div>Third</div>
</AddProps>

Children.forEach

Iterate over children without returning anything.
import { Children } from 'preact/compat';

function LogChildren({ children }) {
  Children.forEach(children, (child, index) => {
    console.log(`Child ${index}:`, child);
  });
  
  return <div>{children}</div>;
}

// Usage
<LogChildren>
  <span>One</span>
  <span>Two</span>
</LogChildren>

Children.count

Count the number of children.
import { Children } from 'preact/compat';

function ShowCount({ children }) {
  const count = Children.count(children);
  
  return (
    <div>
      <p>Number of children: {count}</p>
      {children}
    </div>
  );
}

// Usage
<ShowCount>
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</ShowCount>
// Shows: "Number of children: 3"

Children.only

Verify that children contains only one child and return it. Throws an error if there are multiple children.
import { Children } from 'preact/compat';

function SingleChild({ children }) {
  // Throws if more than one child
  const child = Children.only(children);
  
  return <div className="wrapper">{child}</div>;
}

// Valid usage
<SingleChild>
  <span>Only child</span>
</SingleChild>

// Invalid usage - throws error
<SingleChild>
  <span>First</span>
  <span>Second</span>
</SingleChild>

Children.toArray

Convert children to a flat array of VNodes.
import { Children } from 'preact/compat';

function FlattenChildren({ children }) {
  const childArray = Children.toArray(children);
  
  return (
    <ul>
      {childArray.map((child, index) => (
        <li key={index}>{child}</li>
      ))}
    </ul>
  );
}

// Usage
<FlattenChildren>
  <span>One</span>
  {['Two', 'Three']}
  <span>Four</span>
</FlattenChildren>
// Flattens to 4 items

Implementation Details

The Children implementation in Preact:
import { toChildArray } from 'preact';

const mapFn = (children, fn, context) => {
  if (children == null) return null;
  return toChildArray(toChildArray(children).map(fn.bind(context)));
};

export const Children = {
  map: mapFn,
  forEach: mapFn,
  count(children) {
    return children ? toChildArray(children).length : 0;
  },
  only(children) {
    const normalized = toChildArray(children);
    if (normalized.length !== 1) throw 'Children.only';
    return normalized[0];
  },
  toArray: toChildArray
};

Key Features

  1. Null Handling: Safely handles null or undefined children
  2. Flattening: Uses toChildArray from Preact core to flatten nested arrays
  3. Context Binding: Supports binding a context object for map and forEach
  4. Validation: only throws an error if multiple children are present

Common Use Cases

Adding Props to All Children

import { Children, cloneElement } from 'preact/compat';

function EnhanceChildren({ children, extraProp }) {
  return (
    <div>
      {Children.map(children, child => 
        cloneElement(child, { extraProp })
      )}
    </div>
  );
}

// Usage
<EnhanceChildren extraProp="value">
  <Child1 />
  <Child2 />
</EnhanceChildren>

Filtering Children

import { Children } from 'preact/compat';

function FilterChildren({ children, filterType }) {
  const filtered = Children.toArray(children).filter(
    child => child.type === filterType
  );
  
  return <div>{filtered}</div>;
}

// Usage
function Button() { return <button>Click</button>; }
function Link() { return <a href="#">Link</a>; }

<FilterChildren filterType={Button}>
  <Button />
  <Link />
  <Button />
</FilterChildren>
// Only renders Button components

Conditional Rendering

import { Children } from 'preact/compat';

function ShowIfMultiple({ children, fallback }) {
  const count = Children.count(children);
  
  if (count < 2) {
    return fallback || <div>Need at least 2 children</div>;
  }
  
  return <div>{children}</div>;
}

Wrapping Each Child

import { Children } from 'preact/compat';

function WrapChildren({ children, wrapper: Wrapper }) {
  return (
    <>
      {Children.map(children, (child, index) => (
        <Wrapper key={index}>{child}</Wrapper>
      ))}
    </>
  );
}

// Usage
<WrapChildren wrapper={({ children }) => <div className="item">{children}</div>}>
  <span>One</span>
  <span>Two</span>
  <span>Three</span>
</WrapChildren>
// Each child is wrapped in a div.item

When NOT to Use Children

In most cases, you don’t need the Children API in Preact:

Direct Array Methods

// Instead of Children.map:
function Component({ children }) {
  return <div>{children}</div>;
}

// Or use array methods directly if needed:
function Component({ items }) {
  return (
    <div>
      {items.map((item, i) => <Item key={i} {...item} />)}
    </div>
  );
}

Array.isArray Check

// Instead of Children.count:
function Component({ children }) {
  const count = Array.isArray(children) ? children.length : children ? 1 : 0;
  return <div>Count: {count}</div>;
}

Direct Render

// Instead of Children.toArray:
function Component({ children }) {
  // Preact handles arrays automatically
  return <div>{children}</div>;
}

With TypeScript

Type the children parameter:
import { Children, ComponentChildren, ComponentChild } from 'preact/compat';

interface Props {
  children: ComponentChildren;
}

function Component({ children }: Props) {
  const count = Children.count(children);
  
  return (
    <div>
      <p>Count: {count}</p>
      {children}
    </div>
  );
}

Performance Considerations

  1. Overhead: Children methods add overhead - avoid if not needed
  2. Direct Arrays: Use array methods directly when possible
  3. Keys: Always provide keys when using Children.map
  4. Immutability: Children.map creates new arrays - be mindful in hot paths

Best Practices

  1. Prefer Direct Rendering: Use {children} directly when possible
  2. Type Safety: Use TypeScript for better type checking
  3. Keys: Always provide keys when mapping children
  4. Validation: Use Children.only for components expecting single children
  5. Error Handling: Handle the case when Children.only throws

Comparison with React

Preact’s Children API is compatible with React’s, but simpler:
  • No Children.map context parameter in Preact: The third parameter is supported but rarely used
  • Simpler implementation: Built on top of Preact’s toChildArray
  • Full compatibility: Works with React code expecting the Children API

Source

Implementation: compat/src/Children.js:1-22

Build docs developers (and LLMs) love