Essential components for controlling floating element layout, portaling to different DOM locations, overlays for modal behavior, and visual presentation enhancements.
Portals floating elements to a specified container or creates a new container, with optional tab order preservation.
/**
* Portals floating elements to specified container
* @param props - Portal configuration
* @returns Portal component for DOM placement
*/
interface FloatingPortalProps {
children?: React.ReactNode;
id?: string;
root?: HTMLElement | ShadowRoot | null | React.MutableRefObject<HTMLElement | ShadowRoot | null>;
preserveTabOrder?: boolean;
}
declare const FloatingPortal: React.FC<FloatingPortalProps>;Usage Examples:
import { FloatingPortal, useFloating } from '@floating-ui/react';
import { useState } from 'react';
// Basic portal to document.body
function BasicPortal() {
const [isOpen, setIsOpen] = useState(false);
const { refs, floatingStyles } = useFloating();
return (
<>
<button ref={refs.setReference} onClick={() => setIsOpen(!isOpen)}>
Toggle
</button>
{isOpen && (
<FloatingPortal>
<div
ref={refs.setFloating}
style={{
...floatingStyles,
background: 'white',
border: '1px solid black',
padding: '8px',
}}
>
Portaled content
</div>
</FloatingPortal>
)}
</>
);
}
// Portal to custom container
function CustomPortal() {
const [isOpen, setIsOpen] = useState(false);
const [containerRef, setContainerRef] = useState<HTMLElement | null>(null);
const { refs, floatingStyles } = useFloating();
return (
<>
<div ref={setContainerRef} style={{ position: 'relative' }}>
Custom container
</div>
<button ref={refs.setReference} onClick={() => setIsOpen(!isOpen)}>
Toggle
</button>
{isOpen && (
<FloatingPortal root={containerRef}>
<div
ref={refs.setFloating}
style={{
...floatingStyles,
background: 'lightblue',
padding: '8px',
}}
>
Content in custom container
</div>
</FloatingPortal>
)}
</>
);
}
// Portal with tab order preservation
function TabOrderPortal() {
const [isOpen, setIsOpen] = useState(false);
const { refs, floatingStyles } = useFloating();
return (
<>
<button>Before</button>
<button ref={refs.setReference} onClick={() => setIsOpen(!isOpen)}>
Toggle Portal
</button>
<button>After</button>
{isOpen && (
<FloatingPortal preserveTabOrder>
<div
ref={refs.setFloating}
style={{
...floatingStyles,
background: 'white',
border: '1px solid black',
padding: '8px',
}}
>
<button>Portal Button 1</button>
<button>Portal Button 2</button>
</div>
</FloatingPortal>
)}
</>
);
}Creates a fixed overlay behind floating elements for modal behavior and visual separation.
/**
* Fixed overlay for modal behavior and visual separation
* @param props - Overlay configuration
* @returns Overlay component for modal backgrounds
*/
interface FloatingOverlayProps {
children?: React.ReactNode;
lockScroll?: boolean;
style?: React.CSSProperties;
className?: string;
}
declare const FloatingOverlay: React.FC<FloatingOverlayProps>;Usage Examples:
import {
FloatingOverlay,
FloatingPortal,
FloatingFocusManager,
useFloating,
useClick,
useDismiss,
useInteractions
} from '@floating-ui/react';
import { useState } from 'react';
// Modal dialog with overlay
function ModalDialog() {
const [isOpen, setIsOpen] = useState(false);
const { refs, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
});
const click = useClick(context);
const dismiss = useDismiss(context, {
outsidePress: false, // Prevent closing on overlay click
});
const { getReferenceProps, getFloatingProps } = useInteractions([
click,
dismiss,
]);
return (
<>
<button ref={refs.setReference} {...getReferenceProps()}>
Open Modal
</button>
{isOpen && (
<FloatingPortal>
<FloatingOverlay
lockScroll
style={{ background: 'rgba(0, 0, 0, 0.5)' }}
>
<FloatingFocusManager context={context} modal>
<div
ref={refs.setFloating}
{...getFloatingProps()}
style={{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
background: 'white',
border: '1px solid black',
borderRadius: '8px',
padding: '1rem',
maxWidth: '400px',
}}
>
<h2>Modal Title</h2>
<p>Modal content goes here.</p>
<button onClick={() => setIsOpen(false)}>Close</button>
</div>
</FloatingFocusManager>
</FloatingOverlay>
</FloatingPortal>
)}
</>
);
}
// Clickable overlay to close
function ClickableOverlay() {
const [isOpen, setIsOpen] = useState(false);
const { refs } = useFloating();
return (
<>
<button ref={refs.setReference} onClick={() => setIsOpen(!isOpen)}>
Open with Clickable Overlay
</button>
{isOpen && (
<FloatingPortal>
<FloatingOverlay
lockScroll
style={{ background: 'rgba(0, 0, 0, 0.3)' }}
onClick={() => setIsOpen(false)}
>
<div
ref={refs.setFloating}
onClick={(e) => e.stopPropagation()} // Prevent overlay close
style={{
position: 'fixed',
top: '20%',
left: '50%',
transform: 'translateX(-50%)',
background: 'white',
padding: '1rem',
borderRadius: '4px',
}}
>
<p>Click overlay to close</p>
</div>
</FloatingOverlay>
</FloatingPortal>
)}
</>
);
}
// Custom styled overlay
function CustomOverlay() {
const [isOpen, setIsOpen] = useState(false);
const { refs } = useFloating();
return (
<>
<button ref={refs.setReference} onClick={() => setIsOpen(!isOpen)}>
Custom Overlay
</button>
{isOpen && (
<FloatingPortal>
<FloatingOverlay
className="custom-overlay"
style={{
background: 'linear-gradient(45deg, rgba(255,0,0,0.1), rgba(0,0,255,0.1))',
backdropFilter: 'blur(2px)',
}}
>
<div
ref={refs.setFloating}
style={{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
background: 'white',
padding: '2rem',
borderRadius: '12px',
boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1)',
}}
>
<p>Custom styled overlay</p>
<button onClick={() => setIsOpen(false)}>Close</button>
</div>
</FloatingOverlay>
</FloatingPortal>
)}
</>
);
}SVG arrow component that points from the floating element to its reference element.
/**
* SVG arrow pointing from floating element to reference
* @param props - Arrow configuration
* @returns SVG arrow component
*/
interface FloatingArrowProps {
context: FloatingContext;
width?: number;
height?: number;
tipRadius?: number;
staticOffset?: string | number | null;
strokeWidth?: number;
stroke?: string;
fill?: string;
d?: string;
style?: React.CSSProperties;
className?: string;
}
declare const FloatingArrow: React.FC<FloatingArrowProps>;Usage Examples:
import {
FloatingArrow,
useFloating,
useHover,
useInteractions,
arrow,
offset,
flip,
shift
} from '@floating-ui/react';
import { useState, useRef } from 'react';
// Basic arrow tooltip
function ArrowTooltip() {
const [isOpen, setIsOpen] = useState(false);
const arrowRef = useRef<SVGSVGElement>(null);
const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
middleware: [
offset(10),
flip(),
shift({ padding: 5 }),
arrow({ element: arrowRef }),
],
});
const hover = useHover(context);
const { getReferenceProps, getFloatingProps } = useInteractions([hover]);
return (
<>
<button ref={refs.setReference} {...getReferenceProps()}>
Hover for tooltip
</button>
{isOpen && (
<div
ref={refs.setFloating}
style={{
...floatingStyles,
background: 'black',
color: 'white',
padding: '8px 12px',
borderRadius: '4px',
fontSize: '14px',
}}
{...getFloatingProps()}
>
Tooltip with arrow
<FloatingArrow
ref={arrowRef}
context={context}
fill="black"
/>
</div>
)}
</>
);
}
// Custom styled arrow
function CustomArrow() {
const [isOpen, setIsOpen] = useState(false);
const arrowRef = useRef<SVGSVGElement>(null);
const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
middleware: [
offset(15),
arrow({ element: arrowRef }),
],
});
const hover = useHover(context);
const { getReferenceProps, getFloatingProps } = useInteractions([hover]);
return (
<>
<button ref={refs.setReference} {...getReferenceProps()}>
Custom Arrow
</button>
{isOpen && (
<div
ref={refs.setFloating}
style={{
...floatingStyles,
background: 'lightblue',
border: '2px solid darkblue',
padding: '12px',
borderRadius: '8px',
}}
{...getFloatingProps()}
>
Custom arrow styling
<FloatingArrow
ref={arrowRef}
context={context}
width={16}
height={8}
tipRadius={2}
fill="lightblue"
stroke="darkblue"
strokeWidth={2}
/>
</div>
)}
</>
);
}
// Arrow with different shapes
function CustomShapeArrow() {
const [isOpen, setIsOpen] = useState(false);
const arrowRef = useRef<SVGSVGElement>(null);
const { refs, floatingStyles, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
middleware: [offset(12), arrow({ element: arrowRef })],
});
const hover = useHover(context);
const { getReferenceProps, getFloatingProps } = useInteractions([hover]);
return (
<>
<button ref={refs.setReference} {...getReferenceProps()}>
Custom Shape Arrow
</button>
{isOpen && (
<div
ref={refs.setFloating}
style={{
...floatingStyles,
background: 'purple',
color: 'white',
padding: '10px',
borderRadius: '6px',
}}
{...getFloatingProps()}
>
Custom arrow shape
<FloatingArrow
ref={arrowRef}
context={context}
d="M0,0 L0,8 L8,4 z" // Custom path for arrow shape
fill="purple"
/>
</div>
)}
</>
);
}Creates or accesses a portal node for floating elements.
/**
* Creates or accesses portal node for floating elements
* @param props - Portal node configuration
* @returns Portal node and setters
*/
function useFloatingPortalNode(
props?: UseFloatingPortalNodeProps
): {
portalNode: HTMLElement | null;
setPortalNode: React.Dispatch<React.SetStateAction<HTMLElement | null>>;
};
interface UseFloatingPortalNodeProps {
id?: string;
enabled?: boolean;
}Accesses the current portal context and configuration.
/**
* Access current portal context
* @returns Portal context information
*/
function usePortalContext(): {
portalNode: HTMLElement | null;
setPortalNode: React.Dispatch<React.SetStateAction<HTMLElement | null>>;
preserveTabOrder?: boolean;
} | null;Usage Example:
import { useFloatingPortalNode, usePortalContext } from '@floating-ui/react';
function CustomPortalComponent() {
const { portalNode, setPortalNode } = useFloatingPortalNode({
id: 'custom-portal',
});
const portalContext = usePortalContext();
return (
<div>
<p>Portal node: {portalNode?.id}</p>
<p>Context available: {portalContext ? 'Yes' : 'No'}</p>
</div>
);
}<FloatingPortal>
<FloatingOverlay lockScroll>
<FloatingFocusManager context={context} modal>
{/* Modal content */}
</FloatingFocusManager>
</FloatingOverlay>
</FloatingPortal><FloatingPortal>
<div style={floatingStyles}>
{/* Tooltip content */}
<FloatingArrow ref={arrowRef} context={context} />
</div>
</FloatingPortal><FloatingPortal preserveTabOrder>
<div style={floatingStyles}>
{/* Dropdown content */}
</div>
</FloatingPortal>Portals automatically handle z-index stacking by rendering to document.body or specified containers.
Components support CSS custom properties for theming:
.floating-overlay {
--overlay-background: rgba(0, 0, 0, 0.5);
--overlay-backdrop-filter: blur(4px);
}Layout components work with responsive middleware and viewport detection for optimal mobile and desktop experiences.