Try @eslint-react/kit@beta
logoESLint React

Custom Rules Of Children

Validates React Children API usage.

Overview

This recipe contains five custom rules for validating React Children API usage:

  1. noChildrenCount: Reports the use of Children.count from the 'react' package.
  2. noChildrenForEach: Reports the use of Children.forEach from the 'react' package.
  3. noChildrenMap: Reports the use of Children.map from the 'react' package.
  4. noChildrenOnly: Reports the use of Children.only from the 'react' package.
  5. noChildrenToArray: Reports the use of Children.toArray from the 'react' package.

noChildrenCount

Rule

Copy the following into your project (e.g. .config/noChildrenCount.ts):

.config/noChildrenCount.ts
import type { RuleFunction } from "@eslint-react/kit";

/** Disallow the use of Children.count. */
export function noChildrenCount(): RuleFunction {
  return (context, { is }) => ({
    CallExpression(node) {
      if (is.childrenCountCall(node)) {
        context.report({
          node,
          message: "Using 'Children.count' is uncommon and can lead to fragile code. Use alternatives instead.",
        });
      }
    },
  });
}

Config

eslint.config.ts
import eslintReactKit from "@eslint-react/kit";
import { noChildrenCount } from "./.config/noChildrenCount";

export default [
  // ... other configs
  {
    ...eslintReactKit()
      .use(noChildrenCount)
      .getConfig(),
    files: ["src/**/*.tsx"],
  },
];

Examples

Using the discouraged Children API

import { Children } from "react";

function MyComponent({ children }) {
  // Problem: Using 'Children.count' is uncommon and can lead to fragile code. Use alternatives instead.
  return <h1>Total: {Children.count(children)}</h1>;
}

Using standard alternatives

function MyComponent({ children }) {
  const count = Array.isArray(children) ? children.length : 0;
  return <h1>Total: {count}</h1>;
}

Reports when Children.count is used. This API is fragile because it doesn't work well with fragments, renders, and other modern React patterns.

noChildrenForEach

Rule

Copy the following into your project (e.g. .config/noChildrenForEach.ts):

.config/noChildrenForEach.ts
import type { RuleFunction } from "@eslint-react/kit";

/** Disallow the use of Children.forEach. */
export function noChildrenForEach(): RuleFunction {
  return (context, { is }) => ({
    CallExpression(node) {
      if (is.childrenForEachCall(node)) {
        context.report({
          node,
          message: "Using 'Children.forEach' is uncommon and can lead to fragile code. Use alternatives instead.",
        });
      }
    },
  });
}

Config

eslint.config.ts
import eslintReactKit from "@eslint-react/kit";
import { noChildrenForEach } from "./.config/noChildrenForEach";

export default [
  // ... other configs
  {
    ...eslintReactKit()
      .use(noChildrenForEach)
      .getConfig(),
    files: ["src/**/*.tsx"],
  },
];

Examples

Using the discouraged Children API

import { Children } from "react";

function MyComponent({ children }) {
  const result = [];
  // Problem: Using 'Children.forEach' is uncommon and can lead to fragile code. Use alternatives instead.
  Children.forEach(children, (child, index) => {
    result.push(child);
    result.push(<hr key={index} />);
  });
}

Using standard alternatives

function MyComponent({ children }) {
  return (
    <>
      {Array.isArray(children) && children.map((child, index) => (
        <React.Fragment key={index}>
          {child}
          <hr />
        </React.Fragment>
      ))}
    </>
  );
}

Reports when Children.forEach is used. Use standard array methods or JSX transformation patterns instead.

noChildrenMap

Rule

Copy the following into your project (e.g. .config/noChildrenMap.ts):

.config/noChildrenMap.ts
import type { RuleFunction } from "@eslint-react/kit";

/** Disallow the use of Children.map. */
export function noChildrenMap(): RuleFunction {
  return (context, { is }) => ({
    CallExpression(node) {
      if (is.childrenMapCall(node)) {
        context.report({
          node,
          message: "Using 'Children.map' is uncommon and can lead to fragile code. Use alternatives instead.",
        });
      }
    },
  });
}

Config

eslint.config.ts
import eslintReactKit from "@eslint-react/kit";
import { noChildrenMap } from "./.config/noChildrenMap";

export default [
  // ... other configs
  {
    ...eslintReactKit()
      .use(noChildrenMap)
      .getConfig(),
    files: ["src/**/*.tsx"],
  },
];

Examples

Using the discouraged Children API

import { Children } from "react";

function MyComponent({ children }) {
  return (
    <div className="RowList">
      {/* Problem: Using 'Children.map' is uncommon and can lead to fragile code. Use alternatives instead. */}
      {Children.map(children, (child) => <div className="Row">{child}</div>)}
    </div>
  );
}

Using standard alternatives

function MyComponent({ children }) {
  return (
    <div className="RowList">
      {Array.isArray(children) && children.map((child, i) => (
        <div className="Row" key={i}>{child}</div>
      ))}
    </div>
  );
}

Reports when Children.map is used. This pattern is rarely needed in modern React; instead, render children directly or use standard array methods.

noChildrenOnly

Rule

Copy the following into your project (e.g. .config/noChildrenOnly.ts):

.config/noChildrenOnly.ts
import type { RuleFunction } from "@eslint-react/kit";

/** Disallow the use of Children.only. */
export function noChildrenOnly(): RuleFunction {
  return (context, { is }) => ({
    CallExpression(node) {
      if (is.childrenOnlyCall(node)) {
        context.report({
          node,
          message: "Using 'Children.only' is uncommon and can lead to fragile code. Use alternatives instead.",
        });
      }
    },
  });
}

Config

eslint.config.ts
import eslintReactKit from "@eslint-react/kit";
import { noChildrenOnly } from "./.config/noChildrenOnly";

export default [
  // ... other configs
  {
    ...eslintReactKit()
      .use(noChildrenOnly)
      .getConfig(),
    files: ["src/**/*.tsx"],
  },
];

Examples

Using the discouraged Children API

import { Children } from "react";

function MyComponent({ children }) {
  // Problem: Using 'Children.only' is uncommon and can lead to fragile code. Use alternatives instead.
  const element = Children.only(children);
  // ...
}

Using standard alternatives

import { isValidElement } from "react";

function MyComponent({ children }) {
  if (!isValidElement(children)) {
    throw new Error("Expected a single React element child");
  }
  const element = children;
  // ...
}

Reports when Children.only is used. This API throws if children is not a single element. Use type checks or explicit validation instead for clearer error handling.

noChildrenToArray

Rule

Copy the following into your project (e.g. .config/noChildrenToArray.ts):

.config/noChildrenToArray.ts
import type { RuleFunction } from "@eslint-react/kit";

/** Disallow the use of Children.toArray. */
export function noChildrenToArray(): RuleFunction {
  return (context, { is }) => ({
    CallExpression(node) {
      if (is.childrenToArrayCall(node)) {
        context.report({
          node,
          message: "Using 'Children.toArray' is uncommon and can lead to fragile code. Use alternatives instead.",
        });
      }
    },
  });
}

Config

eslint.config.ts
import eslintReactKit from "@eslint-react/kit";
import { noChildrenToArray } from "./.config/noChildrenToArray";

export default [
  // ... other configs
  {
    ...eslintReactKit()
      .use(noChildrenToArray)
      .getConfig(),
    files: ["src/**/*.tsx"],
  },
];

Examples

Using the discouraged Children API

import { Children } from "react";

function MyComponent({ children }) {
  // Problem: Using 'Children.toArray' is uncommon and can lead to fragile code. Use alternatives instead.
  const result = Children.toArray(children);
  result.reverse();
  // ...
}

Using standard alternatives

function MyComponent({ children }) {
  const result = Array.isArray(children) ? [...children] : [children];
  // ...
}

Reports when Children.toArray is used. This API is typically a workaround for poor component design. Restructure your props or use standard React patterns instead.

Using All Rules

To use all five rules together:

eslint.config.ts
import eslintReactKit from "@eslint-react/kit";
import {
  noChildrenCount,
  noChildrenForEach,
  noChildrenMap,
  noChildrenOnly,
  noChildrenToArray,
} from "./.config";

export default [
  // ... other configs
  {
    ...eslintReactKit()
      .use(noChildrenCount)
      .use(noChildrenForEach)
      .use(noChildrenMap)
      .use(noChildrenOnly)
      .use(noChildrenToArray)
      .getConfig(),
    files: ["src/**/*.tsx"],
  },
];

Further Reading

Resources

  • AST Explorer - A tool for exploring the abstract syntax tree (AST) of JavaScript code, which is essential for writing custom rules.
  • ESLint Developer Guide - Official ESLint documentation for creating custom rules.
  • Using the TypeScript Compiler API - TypeScript compiler API documentation for working with type information in custom rules.

See Also

  • custom-rules-of-context
    Validates React Context API usage. Includes checks for useContext and other context-related patterns.

On this page