Get text content from React children

How to get text content from React children

Sometimes you end up in a scenario where you need to get the .textContent of React children.

For example, let's imagine you have a Toast component that opens a floating notification with a message. You might not want to have duplicated toasts, so you either need to apply some kind of ID or get the text content of the toast.

If your API looks like this:

const { openToast } = useToast();
 
<button onClick={() => openToast({ children: 'Hello, world!' })}>
  Open toast
</button>;

Then you don't have to do any hacky stuff; you can just check if there are any toasts with a message like this in your state. But... what if the hook accepts not only a string, but also a ReactNode?

const { openToast } = useToast();
 
<button onClick={() => openToast({ children: <div>Hello, world!</div> })}>
  Open toast
</button>;

In this case, you need to somehow extract the text content from the ReactNode. You can do that by iterating over the children using the native Children.toArray utility from React. Here's the helper function I found on GitHub Discussions that does exactly that:

import {
  Children,
  type ReactElement,
  type ReactNode,
  isValidElement,
} from 'react';
 
export const transformChildrenToString = (
  children: ReactNode | ReactNode[]
): string => {
  if (!Array.isArray(children) && !isValidElement(children)) {
    return childToString(children);
  }
 
  return Children.toArray(children).reduce(
    (text: string, child: ReactNode): string => {
      let newText = '';
 
      if (hasChildren(child)) {
        newText = transformChildrenToString(child.props.children);
      } else if (isValidElement(child)) {
        newText = '';
      } else {
        newText = childToString(child);
      }
 
      return text.concat(newText);
    },
    ''
  );
};
 
const childToString = (child?: ReactNode): string => {
  if (
    typeof child === 'undefined' ||
    child === null ||
    typeof child === 'boolean'
  ) {
    return '';
  }
 
  if (JSON.stringify(child) === '{}') {
    return '';
  }
 
  return child.toString();
};
 
const hasChildren = (
  element: ReactNode
): element is ReactElement<{ children: ReactNode | ReactNode[] }> =>
  isValidElement<{ children?: ReactNode[] }>(element) &&
  Boolean(element.props.children);

Published on May 21, 2025 2 min read