"Received true for a non-boolean attribute" (or its false counterpart) fires when React renders a custom or non-standard HTML attribute with a boolean value that the DOM doesn't actually treat as a boolean attribute — React passes it through to the actual DOM element, and the browser stringifies it in a way that often isn't what you intended.
This warning means you passed a boolean value (true/false) as a prop that React is forwarding directly to the underlying DOM element as an attribute, but that specific attribute isn't one of the DOM's recognized boolean attributes (like disabled, checked, hidden) — for genuine boolean DOM attributes, React handles the boolean-to-attribute-presence conversion correctly; for anything else, the literal string "true" or "false" gets set, which is usually not the intended behavior.
Why This Error Happens
The DOM has a specific, limited set of attributes that are genuinely boolean in HTML semantics — their mere presence (regardless of value) means true, and their absence means false (disabled, checked, required, hidden, and a handful of others). React knows this specific list and handles those attributes specially, omitting them entirely from the DOM when false and including them (without a value, or as an empty string) when true. Any other attribute name receiving a boolean value doesn't get this special treatment — it becomes a literal attributename="true" string attribute, which usually isn't meaningful HTML and is why React warns about it.
Reproducing the Error
A custom or misspelled attribute name receiving a boolean:
function Card({ isActive }: { isActive: boolean }) {
return <div active={isActive}>Card content</div>;
// Warning: Received `true` for a non-boolean attribute `active`.
// "active" isn't a recognized boolean DOM attribute
}
A data attribute passed without the required data- prefix:
function Item({ selected }: { selected: boolean }) {
return <li selected={selected}>Item</li>;
// Warning: Received `true` for a non-boolean attribute `selected`.
// (unless rendering an <option>, where "selected" is a real boolean attribute)
}
Core Concepts Behind This Error
This is purely about whether the attribute is on the DOM's specific recognized list of genuine boolean attributes, not about whether the value being passed is conceptually a boolean — isActive being a real, meaningful boolean in your component's logic doesn't matter to this warning; what matters is whether active (the actual rendered attribute name) is one the DOM understands as boolean.
Custom data needs to go through data-* or aria-* attributes, which React passes through as-is (as strings), or be handled entirely at the React/JSX level without becoming a literal DOM attribute at all — the fix depends on whether you actually need this information visible in the rendered HTML (use data-*) or whether it's purely for your component's internal logic and styling (don't pass it to the DOM at all).
This most commonly happens when a prop name coincidentally matches a real HTML attribute name that isn't boolean-typed for the element you're using it on, or a custom prop is spread directly onto a DOM element without being filtered out first, letting arbitrary component-level props leak into DOM attributes unintentionally.
Spreading props directly onto a DOM element (<div {...rest}>) is a common source of this warning when rest includes component-specific boolean props not meant for the DOM at all — the fix is destructuring out component-specific props before spreading the remainder onto the DOM element.
Fixing "Received Boolean for a Non-Boolean Attribute"
Fix 1: If you need the value visible in the rendered HTML (for CSS targeting, testing, or debugging), use a data-* attribute, converting to a string explicitly if needed:
function Card({ isActive }: { isActive: boolean }) {
return <div data-active={isActive}>Card content</div>; // valid — data-* accepts any value
}
Fix 2: If the value is purely for component logic (conditional class names, conditional rendering) and doesn't need to appear in the DOM at all, don't pass it as a DOM attribute:
function Card({ isActive }: { isActive: boolean }) {
return <div className={isActive ? "card active" : "card"}>Card content</div>;
}
Fix 3: When spreading props onto a DOM element, destructure out component-specific props first, ensuring only genuine DOM-intended props reach the element:
function Card({ isActive, ...domProps }: CardProps) {
return <div {...domProps} className={isActive ? "active" : ""}>Card content</div>;
}
Fix 4: For attributes genuinely meant to be real DOM boolean attributes, verify the attribute name and element are actually a valid pairing (e.g., selected is boolean specifically on <option>, not general elements):
<select>
<option value="a" selected={isSelected}>Option A</option> {/* valid boolean attribute here */}
</select>
Should You Use data-* Attributes or Just Avoid Passing the Value to the DOM Entirely?
Use data-* when the information genuinely needs to be inspectable in the rendered HTML — for CSS attribute selectors, end-to-end test selectors, or analytics/debugging tooling that reads DOM attributes directly. If the value is purely internal to your component's rendering logic (deciding a class name, conditionally rendering children), there's no need to expose it as a DOM attribute at all — keep it as component-level logic instead, which is simpler and avoids this warning entirely.
Preventing This Error in Production
When passing custom boolean-like props toward a DOM element, default to using them for component logic (class names, conditional rendering) rather than passing them through directly as attributes, reserving data-* specifically for cases where the value needs genuine DOM visibility. When spreading a props object onto a DOM element, always destructure out component-specific props first, keeping the boundary between "props for my component's logic" and "attributes meant for the actual DOM element" explicit and deliberate.
If you hit this warning, decide first whether the value needs to be visible in the rendered HTML at all — if not, keep it out of the DOM attributes entirely; if yes, use data-* rather than a bare custom attribute name.