React library for creating accessible floating UI elements like tooltips, popovers, and dropdowns with advanced positioning
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.