11 KiB
title
| title |
|---|
| <Fragment> (<>...</>) |
<Fragment>, often used via <>...</> syntax, lets you group elements without a wrapper node.
Fragments can also accept refs, which enable interacting with underlying DOM nodes without adding wrapper elements. See reference and usage below.
<>
<OneChild />
<AnotherChild />
</>
Reference {/reference/}
<Fragment> {/fragment/}
Wrap elements in <Fragment> to group them together in situations where you need a single element. Grouping elements in Fragment has no effect on the resulting DOM; it is the same as if the elements were not grouped. The empty JSX tag <></> is shorthand for <Fragment></Fragment> in most cases.
Props {/props/}
- optional
key: Fragments declared with the explicit<Fragment>syntax may have keys. - optional
ref: A ref object (e.g. fromuseRef) or callback function. React provides aFragmentInstanceas the ref value that implements methods for interacting with the DOM nodes wrapped by the Fragment.
FragmentInstance {/fragmentinstance/}
When you pass a ref to a fragment, React provides a FragmentInstance object with methods for interacting with the DOM nodes wrapped by the fragment:
Event handling methods:
addEventListener(type, listener, options?): Adds an event listener to all first-level DOM children of the Fragment.removeEventListener(type, listener, options?): Removes an event listener from all first-level DOM children of the Fragment.dispatchEvent(event): Dispatches an event to a virtual child of the Fragment to call any added listeners and can bubble to the DOM parent.
Layout methods:
compareDocumentPosition(otherNode): Compares the document position of the Fragment with another node.- If the Fragment has children, the native
compareDocumentPositionvalue is returned. - Empty Fragments will attempt to compare positioning within the React tree and include
Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC. - Elements that have a different relationship in the React tree and DOM tree due to portaling or other insertions are
Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC.
- If the Fragment has children, the native
getClientRects(): Returns a flat array ofDOMRectobjects representing the bounding rectangles of all children.getRootNode(): Returns the root node containing the Fragment's parent DOM node.
Focus management methods:
focus(options?): Focuses the first focusable DOM node in the Fragment. Focus is attempted on nested children depth-first.focusLast(options?): Focuses the last focusable DOM node in the Fragment. Focus is attempted on nested children depth-first.blur(): Removes focus ifdocument.activeElementis within the Fragment.
Observer methods:
observeUsing(observer): Starts observing the Fragment's DOM children with an IntersectionObserver or ResizeObserver.unobserveUsing(observer): Stops observing the Fragment's DOM children with the specified observer.
Caveats {/caveats/}
-
If you want to pass
keyto a Fragment, you can't use the<>...</>syntax. You have to explicitly importFragmentfrom'react'and render<Fragment key={yourKey}>...</Fragment>. -
React does not reset state when you go from rendering
<><Child /></>to[<Child />]or back, or when you go from rendering<><Child /></>to<Child />and back. This only works a single level deep: for example, going from<><><Child /></></>to<Child />resets the state. See the precise semantics here. -
If you want to pass
refto a Fragment, you can't use the<>...</>syntax. You have to explicitly importFragmentfrom'react'and render<Fragment ref={yourRef}>...</Fragment>.
Usage {/usage/}
Returning multiple elements {/returning-multiple-elements/}
Use Fragment, or the equivalent <>...</> syntax, to group multiple elements together. You can use it to put multiple elements in any place where a single element can go. For example, a component can only return one element, but by using a Fragment you can group multiple elements together and then return them as a group:
function Post() {
return (
<>
<PostTitle />
<PostBody />
</>
);
}
Fragments are useful because grouping elements with a Fragment has no effect on layout or styles, unlike if you wrapped the elements in another container like a DOM element. If you inspect this example with the browser tools, you'll see that all <h1> and <article> DOM nodes appear as siblings without wrappers around them:
export default function Blog() {
return (
<>
<Post title="An update" body="It's been a while since I posted..." />
<Post title="My new blog" body="I am starting a new blog!" />
</>
)
}
function Post({ title, body }) {
return (
<>
<PostTitle title={title} />
<PostBody body={body} />
</>
);
}
function PostTitle({ title }) {
return <h1>{title}</h1>
}
function PostBody({ body }) {
return (
<article>
<p>{body}</p>
</article>
);
}
How to write a Fragment without the special syntax? {/how-to-write-a-fragment-without-the-special-syntax/}
The example above is equivalent to importing Fragment from React:
import { Fragment } from 'react';
function Post() {
return (
<Fragment>
<PostTitle />
<PostBody />
</Fragment>
);
}
Usually you won't need this unless you need to pass a key to your Fragment.
Assigning multiple elements to a variable {/assigning-multiple-elements-to-a-variable/}
Like any other element, you can assign Fragment elements to variables, pass them as props, and so on:
function CloseDialog() {
const buttons = (
<>
<OKButton />
<CancelButton />
</>
);
return (
<AlertDialog buttons={buttons}>
Are you sure you want to leave this page?
</AlertDialog>
);
}
Grouping elements with text {/grouping-elements-with-text/}
You can use Fragment to group text together with components:
function DateRangePicker({ start, end }) {
return (
<>
From
<DatePicker date={start} />
to
<DatePicker date={end} />
</>
);
}
Rendering a list of Fragments {/rendering-a-list-of-fragments/}
Here's a situation where you need to write Fragment explicitly instead of using the <></> syntax. When you render multiple elements in a loop, you need to assign a key to each element. If the elements within the loop are Fragments, you need to use the normal JSX element syntax in order to provide the key attribute:
function Blog() {
return posts.map(post =>
<Fragment key={post.id}>
<PostTitle title={post.title} />
<PostBody body={post.body} />
</Fragment>
);
}
You can inspect the DOM to verify that there are no wrapper elements around the Fragment children:
import { Fragment } from 'react';
const posts = [
{ id: 1, title: 'An update', body: "It's been a while since I posted..." },
{ id: 2, title: 'My new blog', body: 'I am starting a new blog!' }
];
export default function Blog() {
return posts.map(post =>
<Fragment key={post.id}>
<PostTitle title={post.title} />
<PostBody body={post.body} />
</Fragment>
);
}
function PostTitle({ title }) {
return <h1>{title}</h1>
}
function PostBody({ body }) {
return (
<article>
<p>{body}</p>
</article>
);
}
Using Fragment refs for DOM interaction {/using-fragment-refs-for-dom-interaction/}
Fragment refs allow you to interact with the DOM nodes wrapped by a Fragment without adding extra wrapper elements. This is useful for event handling, visibility tracking, focus management, and replacing deprecated patterns like ReactDOM.findDOMNode().
import { Fragment } from 'react';
function ClickableFragment({ children, onClick }) {
return (
<Fragment ref={fragmentInstance => {
fragmentInstance.addEventListener('click', handleClick);
return () => fragmentInstance.removeEventListener('click', handleClick);
}}>
{children}
</Fragment>
);
}
Tracking visibility with Fragment refs {/tracking-visibility-with-fragment-refs/}
Fragment refs are useful for visibility tracking and intersection observation. This enables you to monitor when content becomes visible without requiring the child Components to expose refs:
import { Fragment, useRef, useLayoutEffect } from 'react';
function VisibilityObserverFragment({ threshold = 0.5, onVisibilityChange, children }) {
const fragmentRef = useRef(null);
useLayoutEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
onVisibilityChange(entries.some(entry => entry.isIntersecting))
},
{ threshold }
);
fragmentRef.current.observeUsing(observer);
return () => fragmentRef.current.unobserveUsing(observer);
}, [threshold, onVisibilityChange]);
return (
<Fragment ref={fragmentRef}>
{children}
</Fragment>
);
}
function MyComponent() {
const handleVisibilityChange = (isVisible) => {
console.log('Component is', isVisible ? 'visible' : 'hidden');
};
return (
<VisibilityObserverFragment onVisibilityChange={handleVisibilityChange}>
<SomeThirdPartyComponent />
<AnotherComponent />
</VisibilityObserverFragment>
);
}
This pattern is an alternative to Effect-based visibility logging, which is an anti-pattern in most cases. Relying on Effects alone does not guarantee that the rendered Component is observable by the user.
Focus management with Fragment refs {/focus-management-with-fragment-refs/}
Fragment refs provide focus management methods that work across all DOM nodes within the Fragment:
import { Fragment, useRef } from 'react';
function FocusFragment({ children }) {
const fragmentRef = useRef(null);
return (
<Fragment ref={(fragmentInstance) => fragmentInstance?.focus()}>
{children}
</Fragment>
);
}
The focus() method focuses the first focusable element within the Fragment, while focusLast() focuses the last focusable element.