CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-floating-ui--react

React library for creating accessible floating UI elements like tooltips, popovers, and dropdowns with advanced positioning

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

layout-components.mddocs/

Layout Components

Essential components for controlling floating element layout, portaling to different DOM locations, overlays for modal behavior, and visual presentation enhancements.

Capabilities

FloatingPortal Component

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>
      )}
    </>
  );
}

FloatingOverlay Component

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>
      )}
    </>
  );
}

FloatingArrow Component

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>
      )}
    </>
  );
}

Portal Context Hooks

useFloatingPortalNode Hook

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;
}

usePortalContext Hook

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>
  );
}

Layout Patterns

Modal Layouts

<FloatingPortal>
  <FloatingOverlay lockScroll>
    <FloatingFocusManager context={context} modal>
      {/* Modal content */}
    </FloatingFocusManager>
  </FloatingOverlay>
</FloatingPortal>

Tooltip Layouts

<FloatingPortal>
  <div style={floatingStyles}>
    {/* Tooltip content */}
    <FloatingArrow ref={arrowRef} context={context} />
  </div>
</FloatingPortal>

Dropdown Layouts

<FloatingPortal preserveTabOrder>
  <div style={floatingStyles}>
    {/* Dropdown content */}
  </div>
</FloatingPortal>

Styling Considerations

Z-Index Management

Portals automatically handle z-index stacking by rendering to document.body or specified containers.

CSS Custom Properties

Components support CSS custom properties for theming:

.floating-overlay {
  --overlay-background: rgba(0, 0, 0, 0.5);
  --overlay-backdrop-filter: blur(4px);
}

Responsive Design

Layout components work with responsive middleware and viewport detection for optimal mobile and desktop experiences.

docs

core-positioning.md

focus-management.md

index.md

interaction-hooks.md

layout-components.md

list-navigation.md

positioning-middleware.md

transitions.md

tree-context.md

tile.json