facebook/react · error · Error
${tag} is a self-closing tag and must neither have `children
Error message
${tag} is a self-closing tag and must neither have `children` nor use `dangerouslySetInnerHTML`. What it means
Thrown by the generic pushSelfClosing helper (message interpolates the actual tag name) when one of the void elements it serves — base, area, br, col, embed, hr, keygen, param, source, track, wbr (this helper also serializes meta and img through their own paths) — receives a non-null children or dangerouslySetInnerHTML prop. These tags have no end tag in HTML, so any children would be parsed as siblings and corrupt the document; React aborts instead.
Source
Thrown at packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js:3547
function pushSelfClosing(
target: Array<Chunk | PrecomputedChunk>,
props: Object,
tag: string,
formatContext: FormatContext,
): null {
target.push(startChunkForTag(tag));
for (const propKey in props) {
if (hasOwnProperty.call(props, propKey)) {
const propValue = props[propKey];
if (propValue == null) {
continue;
}
switch (propKey) {
case 'children':
case 'dangerouslySetInnerHTML':
throw new Error(
`${tag} is a self-closing tag and must neither have \`children\` nor ` +
'use `dangerouslySetInnerHTML`.',
);
default:
pushAttribute(target, propKey, propValue);
break;
}
}
}
pushViewTransitionAttributes(target, formatContext);
target.push(endOfStartTagSelfClosing);
return null;
}
function pushStartMenuItem(
target: Array<Chunk | PrecomputedChunk>,View on GitHub (pinned to eafeac097b)
Solutions
- Self-close the element and remove its children entirely
- Strip children before spreading props onto void elements: const {children, ...rest} = props
- If content was intended, move it to a sibling element instead of inside the void tag
Example fix
// before
<br></br>
<hr {...props} /> {/* props.children present */}
// after
<br />
const {children, ...rest} = props;
<hr {...rest} /> Defensive patterns
Strategy: type-guard
Validate before calling
const VOID = new Set(['base','area','br','col','embed','hr','keygen','param','source','track','wbr','meta','link','img','input']);
function safeTagProps(tag: string, props: Record<string, unknown>) {
if (VOID.has(tag)) {
const {children, dangerouslySetInnerHTML, ...rest} = props as any;
return rest;
}
return props;
} Type guard
type VoidElementProps = {children?: never; dangerouslySetInnerHTML?: never}; Prevention
- Never put children inside void elements (br, hr, source, col, track, ...)
- When spreading arbitrary props onto dynamic tags, filter children for known void tags
- Rely on JSX typings for intrinsic void elements in TypeScript
When it happens
Trigger: JSX like <br>spacing</br>, <hr {...props} /> where props contains children, <source src={v}>{label}</source>, <col>{header}</col>, or any void element receiving children via prop spread.
Common situations: Generic HTML-emitting components that spread user props onto arbitrary tags; HTML-to-JSX converters producing closed void tags with content; copy-paste from non-strict templates; children leaking through {...rest} in table/part components (col, source in picture, track in video).
Related errors
- input is a self-closing tag and must neither have `children`
- link is a self-closing tag and must neither have `children`
- Can only set one of `children` or `props.dangerouslySetInner
- menuitems cannot have `children` nor `dangerouslySetInnerHTM
- 60
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/3535a0277c3aab52.
Report an issue: GitHub.