React.Fragment — salvation from div hell or how to stop polluting the DOM?
Unnecessary divs in code annoy me. Seriously. When I open DevTools and see a nesting doll of meaningless wrappers — I want to cry.
Every unnecessary div is not just garbage in the DOM, it is pain for the developer and browser.
Typical picture in DevTools:
<div class="wrapper">
<div class="container">
<div class="inner">
<div class="content">
<div class="item">
<h2>Header</h2>
<p>Text</p>
</div>
</div>
</div>
</div>
</div>What’s wrong with this code?
Fragment allows grouping elements without creating an extra DOM node.
// Full notation
import React, { Fragment } from 'react';
function MyComponent() {
return (
<Fragment>
<h1>Header</h1>
<p>Paragraph</p>
</Fragment>
);
}
// Short notation
function MyComponent() {
return (
<>
<h1>Header</h1>
<p>Paragraph</p>
</>
);
}
// With key (full notation only)
function MyList({ items }) {
return (
<>
{items.map(item => (
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
</Fragment>
))}
</>
);
}// ❌ Bad — unnecessary div
function UserInfo({ user }) {
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<span>{user.role}</span>
</div>
);
}
// ✅ Good — without unnecessary wrapper
function UserInfo({ user }) {
return (
<>
<h2>{user.name}</h2>
<p>{user.email}</p>
<span>{user.role}</span>
</>
);
}Result in DOM:
<!-- With div -->
<div>
<h2>John Doe</h2>
<p>john@example.com</p>
<span>Developer</span>
</div>
<!-- With Fragment -->
<h2>John Doe</h2>
<p>john@example.com</p>
<span>Developer</span>// ❌ Bad — unnecessary div with condition
function ConditionalContent({ showDetails, user }) {
return (
<div className="user-card">
<h3>{user.name}</h3>
{showDetails && (
<div> {/* Unnecessary wrapper! */}
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
<p>Address: {user.address}</p>
</div>
)}
</div>
);
}
// ✅ Good — clean DOM
function ConditionalContent({ showDetails, user }) {
return (
<div className="user-card">
<h3>{user.name}</h3>
{showDetails && (
<>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
<p>Address: {user.address}</p>
</>
)}
</div>
);
}// ❌ Bad — unnecessary divs in list
function DefinitionList({ terms }) {
return (
<dl>
{terms.map(term => (
<div key={term.id}> {/* Semantically wrong! */}
<dt>{term.word}</dt>
<dd>{term.definition}</dd>
</div>
))}
</dl>
);
}
// ✅ Good — semantically correct
function DefinitionList({ terms }) {
return (
<dl>
{terms.map(term => (
<Fragment key={term.id}>
<dt>{term.word}</dt>
<dd>{term.definition}</dd>
</Fragment>
))}
</dl>
);
}// ❌ Bad — breaks table structure
function TableRows({ items, showTotals }) {
return (
<>
{items.map(item => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.price}</td>
</tr>
))}
{showTotals && (
<div> {/* div inside table — nightmare! */}
<tr>
<td>Total:</td>
<td>{calculateTotal(items)}</td>
</tr>
<tr>
<td>Tax:</td>
<td>{calculateTax(items)}</td>
</tr>
</div>
)}
</>
);
}
// ✅ Good — correct table structure
function TableRows({ items, showTotals }) {
return (
<>
{items.map(item => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.price}</td>
</tr>
))}
{showTotals && (
<>
<tr>
<td>Total:</td>
<td>{calculateTotal(items)}</td>
</tr>
<tr>
<td>Tax:</td>
<td>{calculateTax(items)}</td>
</tr>
</>
)}
</>
);
}// ❌ Excess — Fragment for one element
function SingleButton({ onClick, children }) {
return (
<>
<button onClick={onClick}>{children}</button>
</>
);
}
// ✅ Simple and clear
function SingleButton({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}// ✅ Here div is needed for styling
function Card({ title, content }) {
return (
<div className="card"> {/* Needed for CSS */}
<h3 className="card-title">{title}</h3>
<p className="card-content">{content}</p>
</div>
);
}
// ❌ Fragment is inappropriate here
function Card({ title, content }) {
return (
<> {/* How to style the card? */}
<h3 className="card-title">{title}</h3>
<p className="card-content">{content}</p>
</>
);
}// ✅ div is needed for click handling
function ClickableArea({ onAreaClick, children }) {
return (
<div onClick={onAreaClick} className="clickable-area">
{children}
</div>
);
}
// ❌ Fragment cannot handle events
function ClickableArea({ onAreaClick, children }) {
return (
<> {/* onClick doesn't work! */}
{children}
</>
);
}Before (with unnecessary divs):
function ContactForm() {
const [showAdvanced, setShowAdvanced] = useState(false);
return (
<form className="contact-form">
<div> {/* Unnecessary div #1 */}
<label>Name</label>
<input type="text" name="name" />
</div>
<div> {/* Unnecessary div #2 */}
<label>Email</label>
<input type="email" name="email" />
</div>
{showAdvanced && (
<div> {/* Unnecessary div #3 */}
<div> {/* Unnecessary div #4 */}
<label>Phone</label>
<input type="tel" name="phone" />
</div>
<div> {/* Unnecessary div #5 */}
<label>Company</label>
<input type="text" name="company" />
</div>
</div>
)}
<div> {/* Unnecessary div #6 */}
<button type="submit">Submit</button>
<button type="button" onClick={() => setShowAdvanced(!showAdvanced)}>
{showAdvanced ? 'Hide' : 'Show'} additional fields
</button>
</div>
</form>
);
}After (with Fragment):
function ContactForm() {
const [showAdvanced, setShowAdvanced] = useState(false);
return (
<form className="contact-form">
<div className="field-group"> {/* Semantically justified */}
<label>Name</label>
<input type="text" name="name" />
</div>
<div className="field-group"> {/* Semantically justified */}
<label>Email</label>
<input type="email" name="email" />
</div>
{showAdvanced && (
<> {/* Grouping without extra DOM */}
<div className="field-group">
<label>Phone</label>
<input type="tel" name="phone" />
</div>
<div className="field-group">
<label>Company</label>
<input type="text" name="company" />
</div>
</>
)}
<div className="button-group"> {/* Semantically justified */}
<button type="submit">Submit</button>
<button type="button" onClick={() => setShowAdvanced(!showAdvanced)}>
{showAdvanced ? 'Hide' : 'Show'} additional fields
</button>
</div>
</form>
);
}// Component with div
function ItemWithDiv({ title, description }) {
return (
<div>
<h4>{title}</h4>
<p>{description}</p>
</div>
);
}
// Component with Fragment
function ItemWithFragment({ title, description }) {
return (
<>
<h4>{title}</h4>
<p>{description}</p>
</>
);
}Results:
{
"rules": {
"react/jsx-fragments": ["error", "syntax"],
"react/jsx-no-useless-fragment": "error"
}
}{
"jsxBracketSameLine": false,
"jsxSingleQuote": false
}React.Fragment is not just syntactic sugar. It is a tool for:
Remember: every div should be justified. If it doesn’t carry semantic load and isn’t needed for styles — use Fragment.
Golden rule: Don’t breed wrappers for the sake of wrappers. DOM should be clean, like your conscience.
Want more articles about React and frontend? Subscribe to EasyAdvice, bookmark the site and level up every day 💪