Skip to content

🐛 [Bug]: Conditional render of child in React RichText resolver causes crash #266

@FabianKoder

Description

@FabianKoder

Package

@storyblok/richtext (Rich Text Renderer)

Bug Description

I have the following example implementation:

export function ListItem(node: StoryblokRichTextNode<ReactElement>) {
	const settings = useSettings();

	if (node.type !== BlockTypes.LIST_ITEM) {
		return null;
	}

	return (
		<li {...node.attrs}>
			{settings.whatever === 'whatever' && <Whatever />}
			{node.children}
		</li>
	);
}

When the clause is false, a crash with the following error happens: Cannot read properties of null (reading 'props')

The issue comes from this code segment:

// Process children recursively.
const children = React.Children.map((element.props as React.PropsWithChildren).children, (child) => {
if (typeof child === 'string') {
return child;
}
return convertAttributesInElement(child as React.ReactElement);
});

Since a conditional render is basically a falsy value that will not be rendered by React, the implementation will fallback to convert attributes of null and tries to access props of null here:

const newProps: { [key: string]: unknown } = Object.keys((element.props as Record<string, unknown>)).reduce((acc: { [key: string]: unknown }, key) => {

Workaround:

export function ListItem(node: StoryblokRichTextNode<ReactElement>) {
	const settings = useSettings();

	if (node.type !== BlockTypes.LIST_ITEM) {
		return null;
	}

	return (
		<li className='py-1 text-left' {...node.attrs}>
			{settings.whatever === 'whatever' ? <Checkmark /> : <></>}
			{node.children}
		</li>
	);
}

The fragment will still render no visible elements, but it is a valid element with children.

Steps to Reproduce

  1. Render a child of a resolver conditionally
  2. The clause should be false so that the conditionally rendered element will not be rendered
  3. Crash

Expected Behavior

React functionality should not be impacted

Actual Behavior

Conditional rendering in a custom RichText resolver results in a crash

Code Sample

Environment

System:
    OS: macOS 15.5
    CPU: (11) arm64 Apple M3 Pro
    Memory: 204.14 MB / 36.00 GB
    Shell: 3.7.0 - /opt/homebrew/bin/fish
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    npm: 10.8.3 - ~/.nvm/versions/node/v20.11.0/bin/npm
    pnpm: 9.4.0 - ~/.nvm/versions/node/v20.11.0/bin/pnpm
    bun: 1.2.8 - ~/.bun/bin/bun
  Browsers:
    Brave Browser: 138.1.80.115
    Chrome: 139.0.7258.138
    Safari: 18.5
  npmPackages:
    @storyblok/js: 4.2.0 => 4.2.0 
    @storyblok/react: 5.4.0 => 5.4.0 
    next: 15.3.4 => 15.3.4 
    react: 19.0.0 => 19.0.0 
    storyblok: 4.3.4 => 4.3.4

Error Logs

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions