<PageCard>

# FloatingTree

Provides context for nested floating elements when they are not
children of each other on the DOM.

<ShowFor packages={['react-dom']}>

<PackageLimited>@floating-ui/react only</PackageLimited>

</ShowFor>

</PageCard>

This is not necessary in all cases, except when there must be
explicit communication between parent and child floating
elements. It is necessary for:

- The `bubbles{:.key}` option in the `useDismiss(){:js}` Hook
- [Nested virtual list navigation](/docs/useListNavigation#virtualitemref)
- Nested floating elements that each open on hover
- Custom communication between parent and child floating elements

## Usage

The following creates an infinitely nestable `<Popover>{:js}`
component. Usage of this component must be wrapped in a single
`<FloatingTree>{:js}` provider:

```js {10-11,15,25,31,38,48}
import {
  FloatingTree,
  FloatingNode,
  useFloatingNodeId,
} from '@floating-ui/react';

function Popover({children, content}) {
  const [isOpen, setIsOpen] = useState(false);

  // Subscribe this component to the <FloatingTree> wrapper:
  const nodeId = useFloatingNodeId();

  // Pass the subscribed `nodeId` to `useFloating`:
  const {refs, floatingStyles} = useFloating({
    nodeId,
    open: isOpen,
    onOpenChange: setIsOpen,
  });

  // Wrap the rendered floating element in a `<FloatingNode>`,
  // passing in the subscribed `nodeId`:
  return (
    <>
      {cloneElement(children, {ref: refs.setReference})}
      <FloatingNode id={nodeId}>
        {isOpen && (
          <FloatingPortal>
            <div ref={refs.setFloating}>{content}</div>
          </FloatingPortal>
        )}
      </FloatingNode>
    </>
  );
}

function App() {
  return (
    <FloatingTree>
      <Popover
        content={
          <Popover content="Nested content">
            <button>Nested reference</button>
          </Popover>
        }
      >
        <button>Root reference</button>
      </Popover>
    </FloatingTree>
  );
}
```

## Hooks

- `useFloatingNodeId(){:js}` subscribes the component to the tree
  context. Call this only once as it has side effects.
- `useFloatingParentNodeId(){:js}` returns the parent
  `FloatingNode{:.class}` id, if it exists. This will be
  `null{:js}` for roots (not nested).
- `useFloatingTree(){:js}` for accessing the tree object, which
  includes an event emitter to communicate across the tree
  components (`events{:.key}`).

```js
interface FloatingTreeType {
  nodesRef: React.MutableRefObject<Array<FloatingNodeType>>;
  events: FloatingEvents;
  addNode(node: FloatingNodeType): void;
  removeNode(node: FloatingNodeType): void;
}
```

## Custom parent

By default, the parent node is the closest
`<FloatingNode />{:js}`, but you can specify a custom parent node
by passing in the `parentId` to `useFloatingNodeId(){:js}`:

```js
const nodeId = useFloatingNodeId(parentId);
```

This is useful if you want to mark a sibling floating element in
the React tree as the child of another sibling.

## `<FloatingTree>{:js}` wrapper

You can use the following technique to avoid having the consumer
specify the `<FloatingTree>{:js}` wrapper:

```js
function PopoverComponent() {
  // Main logic as seen earlier
}

// This is the component the consumer uses
export function Popover(props) {
  const parentId = useFloatingParentNodeId();

  // This is a root, so we wrap it with the tree
  if (parentId === null) {
    return (
      <FloatingTree>
        <PopoverComponent {...props} />
      </FloatingTree>
    );
  }

  return <PopoverComponent {...props} />;
}
```

## Troubleshooting

Ensure that the component that you're calling
`useFloatingNodeId(){:js}` is a _child_ of the
`<FloatingTree>{:js}` wrapper. If it is not, then it will not be
able to find the tree context.
