content/docs/api/floating.mdx
@platejs/floating contains the React hooks and rectangle utilities used by floating toolbars, cursor-anchored UI, and virtual elements in Plate. It wraps Floating UI and exports the Floating UI primitives Plate components use.
npm install @platejs/floating
| Surface | Owner | Use |
|---|---|---|
useVirtualFloating | @platejs/floating | useFloating with a controlled virtual reference element. |
useFloatingToolbarState | @platejs/floating | Builds toolbar state from editor focus, selection, read-only state, and Floating UI options. |
useFloatingToolbar | @platejs/floating | Turns toolbar state into DOM props, ref, outside-click ref, and hidden state. |
| Rect utilities | @platejs/floating | Convert editor ranges, DOM selection, and client rect arrays into Floating UI-compatible rects. |
| Floating UI exports | @platejs/floating | Re-exported middleware and hooks from @floating-ui/react. |
useVirtualFloating creates a Floating UI virtual reference. Use it when the floating element follows a selection, cursor, or computed rectangle instead of a real DOM reference element.
import {
flip,
getDefaultBoundingClientRect,
offset,
useVirtualFloating,
} from '@platejs/floating';
export function SelectionPopover({
open,
rect,
}: {
open: boolean;
rect?: DOMRect;
}) {
const floating = useVirtualFloating({
getBoundingClientRect: () => rect ?? getDefaultBoundingClientRect(),
middleware: [offset(8), flip()],
open,
placement: 'top',
});
return (
<div ref={floating.refs.setFloating} style={floating.style}>
Selection actions
</div>
);
}
Floating toolbar setup is split into two hooks. Build state first, then pass that state to useFloatingToolbar.
import {
flip,
offset,
useFloatingToolbar,
useFloatingToolbarState,
} from '@platejs/floating';
import { useEditorId, useEventEditorValue } from 'platejs/react';
export function ToolbarShell() {
const editorId = useEditorId();
const focusedEditorId = useEventEditorValue('focus');
const state = useFloatingToolbarState({
editorId,
focusedEditorId,
floatingOptions: {
middleware: [offset(12), flip({ padding: 12 })],
placement: 'top',
},
});
const { clickOutsideRef, hidden, props, ref } = useFloatingToolbar(state);
if (hidden) return null;
return (
<div ref={clickOutsideRef}>
<div ref={ref} {...props}>
Toolbar
</div>
</div>
);
}
The toolbar opens only for an expanded selection with text. It stays hidden while the mouse is down, when hideToolbar is true, when a different editor owns focus, or when the editor is read-only and showWhenReadOnly is not set.
These helpers normalize editor locations and DOM ranges into rectangles.
<API name="Rectangle utilities"> <APIMethods> <APIItem name="getDefaultBoundingClientRect" type="() => ClientRectObject"> Returns a zero-size offscreen rect used as a safe Floating UI fallback. </APIItem> <APIItem name="createVirtualElement" type="() => VirtualElement"> Creates a Floating UI virtual element with `getDefaultBoundingClientRect`. </APIItem> <APIItem name="createVirtualRef" type="(editor: Editor, at?: TLocation | TLocation[], options?: { fallbackRect?: ClientRect }) => VirtualRef"> Creates a ref-like object whose `current.getBoundingClientRect()` reads editor locations. It throws when no rect exists and no `fallbackRect` is provided. </APIItem> <APIItem name="getBoundingClientRect" type="(editor: Editor, at?: TLocation | TLocation[]) => DOMRect | undefined"> Reads one or more editor locations, converts them to DOM ranges, and returns the merged bounding rect. If `at` is omitted, it uses `editor.selection`. </APIItem> <APIItem name="getRangeBoundingClientRect" type="(editor: Editor, at: TRange | null) => ClientRectObject"> Returns the DOM rect for a range, or `getDefaultBoundingClientRect()` when the range or DOM range is missing. </APIItem> <APIItem name="getSelectionBoundingClientRect" type="(editor: PlateEditor) => ClientRectObject"> Returns the selection rect only when the editor selection is expanded. Collapsed selections return the default rect. </APIItem> <APIItem name="getDOMSelectionBoundingClientRect" type="() => ClientRectObject"> Returns `window.getSelection().getRangeAt(0).getBoundingClientRect()`, or the default rect when no DOM selection exists. </APIItem> <APIItem name="makeClientRect" type="(rect: { bottom: number; left: number; right: number; top: number }) => DOMRect"> Creates a DOMRect-like object and computes `width`, `height`, `x`, and `y`. </APIItem> <APIItem name="mergeClientRects" type="(clientRects: DOMRect[]) => DOMRect"> Merges client rects by min left/top and max right/bottom. It throws when the array is empty. </APIItem> </APIMethods> </API>@platejs/floating re-exports the Floating UI middleware and React hooks used by Plate UI, including autoUpdate, flip, hide, inline, offset, shift, size, useFloating, useInteractions, useClick, useDismiss, FloatingPortal, and related types.
Use those exports when a Plate UI component already imports from @platejs/floating; use @floating-ui/react directly only when the component is not coupled to Plate.
useEditorId and useEventEditorValue.