React Fragment
React Fragment is a way to group multiple elements without adding extra DOM nodes, providing a cleaner way to return multiple elements from components.
Table of Contents
What is React Fragment?
React Fragment is a special component that allows you to group multiple elements without creating an additional DOM node.
Key Concepts:
- No extra DOM node: Groups elements without wrapper div
- Performance benefit: Reduces DOM complexity
- Clean JSX: Avoids unnecessary wrapper elements
- Multiple syntaxes:
<>shorthand and<React.Fragment>
Problem Fragment Solves:
// Before Fragment: Extra div wrapper
function App() {
return (
<div> {/* Unnecessary wrapper */}
<h1>Title</h1>
<p>Paragraph</p>
<button>Click me</button>
</div>
);
}
// With Fragment: No extra wrapper
function App() {
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
<button>Click me</button>
</>
);
}
Fragment Syntax
1. Shorthand Syntax:
// Short syntax (most common)
function Component() {
return (
<>
<h1>Hello</h1>
<p>World</p>
</>
);
}
// Renders as:
// <h1>Hello</h1>
// <p>World</p>
// (No wrapper element)
2. Full Syntax:
// Full syntax with React.Fragment
import React from 'react';
function Component() {
return (
<React.Fragment>
<h1>Hello</h1>
<p>World</p>
</React.Fragment>
);
}
// Or with destructured import
import React, { Fragment } from 'react';
function Component() {
return (
<Fragment>
<h1>Hello</h1>
<p>World</p>
</Fragment>
);
}
3. Fragment with Keys:
// Fragment with key prop (only available in full syntax)
function List({ items }) {
return (
<React.Fragment>
{items.map(item => (
<React.Fragment key={item.id}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</React.Fragment>
))}
</React.Fragment>
);
}
// Usage
const items = [
{ id: 1, title: 'Item 1', description: 'Description 1' },
{ id: 2, title: 'Item 2', description: 'Description 2' }
];
function App() {
return <List items={items} />;
}
Common Use Cases
1. Returning Multiple Elements:
// Component that needs to return multiple elements
function UserProfile({ user }) {
return (
<>
<h2>{user.name}</h2>
<p>{user.email}</p>
<p>{user.role}</p>
<button>Edit Profile</button>
</>
);
}
// Without Fragment, you'd need a wrapper div
function UserProfileWithDiv({ user }) {
return (
<div className="user-profile"> {/* Extra wrapper */}
<h2>{user.name}</h2>
<p>{user.email}</p>
<p>{user.role}</p>
<button>Edit Profile</button>
</div>
);
}
2. Conditional Rendering:
// Conditional rendering with Fragment
function ConditionalContent({ showHeader, showFooter, children }) {
return (
<>
{showHeader && <header>Header Content</header>}
<main>{children}</main>
{showFooter && <footer>Footer Content</footer>}
</>
);
}
// Usage
function App() {
return (
<ConditionalContent showHeader={true} showFooter={false}>
<p>Main content</p>
</ConditionalContent>
);
}
3. List Rendering:
// Rendering lists without wrapper
function TodoList({ todos }) {
return (
<>
{todos.map(todo => (
<div key={todo.id} className="todo-item">
<span>{todo.text}</span>
<button>Delete</button>
</div>
))}
</>
);
}
// Alternative with Fragment for each item
function TodoListWithFragment({ todos }) {
return (
<>
{todos.map(todo => (
<React.Fragment key={todo.id}>
<span>{todo.text}</span>
<button>Delete</button>
</React.Fragment>
))}
</>
);
}
4. Table Structures:
// Table with Fragment (no extra wrapper)
function TableRow({ cells }) {
return (
<>
{cells.map((cell, index) => (
<td key={index}>{cell}</td>
))}
</>
);
}
// Usage in table
function DataTable({ data }) {
return (
<table>
<tbody>
{data.map((row, rowIndex) => (
<tr key={rowIndex}>
<TableRow cells={row} />
</tr>
))}
</tbody>
</table>
);
}
5. Form Layouts:
// Form with multiple elements
function FormField({ label, error, children }) {
return (
<>
<label>{label}</label>
{children}
{error && <span className="error">{error}</span>}
</>
);
}
// Usage
function ContactForm() {
return (
<form>
<FormField label="Name" error="Name is required">
<input type="text" />
</FormField>
<FormField label="Email">
<input type="email" />
</FormField>
<FormField label="Message">
<textarea />
</FormField>
</form>
);
}
Advanced Fragment Patterns
1. Fragment with Conditional Logic:
// Complex conditional rendering
function ComplexComponent({ user, showDetails, showActions }) {
return (
<>
<h2>{user.name}</h2>
{showDetails && (
<>
<p>Email: {user.email}</p>
<p>Role: {user.role}</p>
<p>Department: {user.department}</p>
</>
)}
{showActions && (
<>
<button>Edit</button>
<button>Delete</button>
<button>Archive</button>
</>
)}
</>
);
}
2. Fragment with HOCs:
// HOC that returns multiple elements
function withHeaderAndFooter(WrappedComponent) {
return function EnhancedComponent(props) {
return (
<>
<header>Header from HOC</header>
<WrappedComponent {...props} />
<footer>Footer from HOC</footer>
</>
);
};
}
// Usage
const EnhancedComponent = withHeaderAndFooter(MyComponent);
3. Fragment with Context:
// Context provider with Fragment
const ThemeContext = React.createContext('light');
function ThemeProvider({ children, theme }) {
return (
<>
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
<style>{`
:root {
--theme: ${theme};
}
`}</style>
</>
);
}
4. Fragment with Portals:
// Component that renders to multiple places
function ModalWithBackdrop({ children, isOpen }) {
if (!isOpen) return null;
return (
<>
{ReactDOM.createPortal(
<div className="backdrop" />,
document.body
)}
{ReactDOM.createPortal(
<div className="modal">{children}</div>,
document.body
)}
</>
);
}
5. Fragment with Error Boundaries:
// Error boundary with Fragment
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return (
<>
<h2>Something went wrong</h2>
<button onClick={() => this.setState({ hasError: false })}>
Try again
</button>
</>
);
}
return this.props.children;
}
}
Best Practices
1. Use Shorthand When Possible:
// Good: Use shorthand for simple cases
function SimpleComponent() {
return (
<>
<h1>Title</h1>
<p>Content</p>
</>
);
}
// Good: Use full syntax when you need keys
function ListWithKeys({ items }) {
return (
<>
{items.map(item => (
<React.Fragment key={item.id}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</React.Fragment>
))}
</>
);
}
2. Don’t Overuse Fragments:
// Good: Use Fragment when you need multiple elements
function GoodComponent() {
return (
<>
<h1>Title</h1>
<p>Content</p>
</>
);
}
// Bad: Don't use Fragment for single element
function BadComponent() {
return (
<>
<h1>Title</h1>
</>
);
// Should just return <h1>Title</h1>
}
3. Consider Semantic HTML:
// Good: Use semantic elements when appropriate
function GoodLayout() {
return (
<>
<header>Header</header>
<main>Main content</main>
<footer>Footer</footer>
</>
);
}
// Bad: Don't use Fragment when semantic wrapper makes sense
function BadLayout() {
return (
<>
<h1>Header</h1>
<p>Main content</p>
<p>Footer</p>
</>
);
// Should use semantic elements or a wrapper
}
4. Handle Keys Properly:
// Good: Use keys with Fragment when needed
function GoodList({ items }) {
return (
<>
{items.map(item => (
<React.Fragment key={item.id}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</React.Fragment>
))}
</>
);
}
// Bad: Missing keys can cause issues
function BadList({ items }) {
return (
<>
{items.map(item => (
<>
<h3>{item.title}</h3>
<p>{item.description}</p>
</>
))}
</>
);
}
5. Consider Performance:
// Good: Fragment reduces DOM nodes
function EfficientComponent() {
return (
<>
<h1>Title</h1>
<p>Content</p>
</>
);
// Only 2 DOM nodes: h1 and p
}
// Bad: Wrapper div adds extra DOM node
function InefficientComponent() {
return (
<div>
<h1>Title</h1>
<p>Content</p>
</div>
);
// 3 DOM nodes: div, h1, and p
}
Common Interview Questions
Q: What is React Fragment?
- A way to group multiple elements without adding extra DOM nodes.
Q: What are the different ways to write Fragment?
- Shorthand syntax
<>and full syntax<React.Fragment>.
Q: When should you use Fragment?
- When you need to return multiple elements from a component without a wrapper.
Q: What’s the difference between Fragment and div?
- Fragment doesn’t create a DOM node, while div creates an extra wrapper element.
Q: Can you use keys with Fragment?
- Yes, but only with the full
<React.Fragment>syntax, not the shorthand<>.
Q: What are the benefits of using Fragment?
- Cleaner DOM structure, better performance, and more semantic HTML.
Q: When should you use div instead of Fragment?
- When you need styling, event handling, or refs on the wrapper element.
Q: Can you nest Fragments?
- Yes, you can nest Fragments, but it’s usually unnecessary.
Q: How does Fragment affect performance?
- Fragment reduces DOM complexity by eliminating unnecessary wrapper nodes.
Q: What’s the difference between Fragment and array return?
- Fragment is more readable and doesn’t require keys for static content.
Summary
- React Fragment allows grouping multiple elements without extra DOM nodes
- Shorthand syntax
<>is preferred for simple cases - Full syntax
<React.Fragment>is needed when keys are required - Common use cases include conditional rendering, lists, and form layouts
- Performance benefit comes from reducing DOM complexity
- Best practices include using semantic HTML when appropriate
- Keys are only available with the full Fragment syntax
- Understanding Fragment is crucial for writing clean, efficient React components
Interview angle
- “Why do fragments exist?” - a component must return one node, and a wrapper div breaks layouts that depend on direct parent-child relationships - flex and grid containers, tables, lists. Fragments group without emitting DOM.
- “When can’t you use the
<>shorthand?” - when you need akey, which is the case whenever you map to fragments. Write<React.Fragment key={id}>. - “Do fragments cost anything?” - a node in the React tree, nothing in the DOM. Fewer DOM nodes is a real win in large lists and tables.