CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-radix-ui--react-dialog

A high-quality, accessible dialog component for React applications, providing overlay modals, focus management, keyboard navigation, and screen reader support as part of the Radix UI primitives collection

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

portal-layout.mddocs/

Portal and Layout

Portal rendering and overlay components for proper dialog layering, modal behavior, and visual presentation.

Capabilities

DialogPortal

Portal component that renders dialog content outside the normal DOM flow for proper layering and z-index management.

/**
 * Portal component that renders children outside normal DOM flow
 * Ensures proper layering and avoids z-index conflicts
 */
type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;

interface DialogPortalProps {
  /** Content to be portaled */
  children?: React.ReactNode;
  /** Custom container element to portal into (defaults to document.body) */
  container?: PortalProps['container'];
  /** Force mounting when more control is needed for animations */
  forceMount?: true;
}

const DialogPortal: React.FC<DialogPortalProps>;

Usage Examples:

import { 
  Dialog, 
  DialogTrigger, 
  DialogPortal, 
  DialogContent 
} from "@radix-ui/react-dialog";

// Basic portal usage
function BasicPortal() {
  return (
    <Dialog>
      <DialogTrigger>Open</DialogTrigger>
      <DialogPortal>
        <DialogContent>
          This content is rendered outside the normal DOM flow
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

// Custom portal container
function CustomContainer() {
  const [container, setContainer] = React.useState<HTMLElement | null>(null);
  
  return (
    <div>
      <div ref={setContainer} id="custom-portal-root" />
      <Dialog>
        <DialogTrigger>Open</DialogTrigger>
        <DialogPortal container={container}>
          <DialogContent>
            This renders into the custom container
          </DialogContent>
        </DialogPortal>
      </Dialog>
    </div>
  );
}

// Force mount for animations
function AnimatedPortal() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger>Open</DialogTrigger>
      <DialogPortal forceMount>
        <DialogContent className={open ? 'fade-in' : 'fade-out'}>
          Always mounted for smooth animations
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

DialogOverlay

Background overlay component that provides visual separation and modal behavior for dialogs.

/**
 * Background overlay component for modal dialogs
 * Provides visual backdrop and handles scroll locking
 * Only renders for modal dialogs (modal={true})
 */
type DialogOverlayElement = React.ComponentRef<typeof Primitive.div>;
interface DialogOverlayProps extends React.ComponentPropsWithoutRef<typeof Primitive.div> {
  /** Force mounting when more control is needed for animations */
  forceMount?: true;
}

const DialogOverlay: React.ForwardRefExoticComponent<
  DialogOverlayProps & React.RefAttributes<DialogOverlayElement>
>;

Usage Examples:

import { 
  Dialog, 
  DialogTrigger, 
  DialogPortal,
  DialogOverlay,
  DialogContent 
} from "@radix-ui/react-dialog";

// Basic overlay usage
function BasicOverlay() {
  return (
    <Dialog>
      <DialogTrigger>Open Modal</DialogTrigger>
      <DialogPortal>
        <DialogOverlay className="dialog-overlay" />
        <DialogContent>
          Modal content with overlay background
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

// Styled overlay
function StyledOverlay() {
  return (
    <Dialog>
      <DialogTrigger>Open</DialogTrigger>
      <DialogPortal>
        <DialogOverlay 
          className="overlay"
          style={{ 
            backgroundColor: 'rgba(0, 0, 0, 0.75)',
            backdropFilter: 'blur(4px)'
          }}
        />
        <DialogContent>Content here</DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

// Overlay with animation
function AnimatedOverlay() {
  return (
    <Dialog>
      <DialogTrigger>Open</DialogTrigger>
      <DialogPortal>
        <DialogOverlay 
          forceMount 
          className="overlay-with-transition"
          data-state={open ? 'open' : 'closed'}
        />
        <DialogContent>Content here</DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

// No overlay for non-modal dialog
function NonModalDialog() {
  return (
    <Dialog modal={false}>
      <DialogTrigger>Open Non-Modal</DialogTrigger>
      <DialogPortal>
        {/* DialogOverlay will not render when modal={false} */}
        <DialogOverlay />
        <DialogContent>
          Non-modal content without blocking overlay
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

Portal Behavior

Default Portal Container

By default, DialogPortal renders content into document.body. This ensures:

  • Content appears above other page elements
  • Proper z-index stacking
  • No overflow clipping from parent containers
  • Accessibility tree structure is maintained

Custom Portal Container

You can specify a custom container for special use cases:

// Portal into a specific element
const portalRoot = document.getElementById('portal-root');

<DialogPortal container={portalRoot}>
  <DialogContent>Custom container content</DialogContent>
</DialogPortal>

Portal and React Context

Portal content maintains access to React context from its original location in the component tree, even though it renders elsewhere in the DOM.

Overlay Behavior

Modal Overlay Features

When modal={true} (default), DialogOverlay provides:

  • Visual Backdrop: Semi-transparent background
  • Scroll Locking: Prevents body scrolling when dialog is open
  • Click Outside: Clicking overlay closes the dialog
  • Focus Management: Helps contain focus within modal content

Overlay Styling

The overlay renders as a div element with:

  • data-state attribute ("open" or "closed")
  • pointer-events: auto style to enable click handling
  • Full viewport coverage positioning
.dialog-overlay {
  position: fixed;
  inset: 0;
  background-color: rgba(0, 0, 0, 0.5);
  animation: fadeIn 150ms ease-out;
}

.dialog-overlay[data-state="closed"] {
  animation: fadeOut 150ms ease-in;
}

Overlay and Animation

Use forceMount to control overlay mounting for animations:

// Overlay always mounted for smooth transitions
<DialogOverlay forceMount data-state={open ? 'open' : 'closed'} />

Layout Patterns

Standard Modal Layout

<Dialog>
  <DialogTrigger>Open</DialogTrigger>
  <DialogPortal>
    <DialogOverlay />
    <DialogContent>
      {/* Dialog content */}
    </DialogContent>
  </DialogPortal>
</Dialog>

Non-Modal Layout

<Dialog modal={false}>
  <DialogTrigger>Open</DialogTrigger>
  <DialogPortal>
    {/* No overlay needed for non-modal */}
    <DialogContent>
      {/* Dialog content */}
    </DialogContent>
  </DialogPortal>
</Dialog>

Custom Container Layout

<div className="app-container">
  <div id="dialog-portal" className="dialog-container" />
  <Dialog>
    <DialogTrigger>Open</DialogTrigger>
    <DialogPortal container={document.getElementById('dialog-portal')}>
      <DialogOverlay />
      <DialogContent>
        {/* Content portaled to custom container */}
      </DialogContent>
    </DialogPortal>
  </Dialog>
</div>

Install with Tessl CLI

npx tessl i tessl/npm-radix-ui--react-dialog

docs

advanced-context.md

content-accessibility.md

dialog-root.md

index.md

portal-layout.md

triggers-controls.md

tile.json