# 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.

```typescript { .api }
/**
 * 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:**

```typescript
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.

```typescript { .api }
/**
 * 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:**

```typescript
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:

```typescript
// 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

```css
.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:

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

## Layout Patterns

### Standard Modal Layout

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

### Non-Modal Layout

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

### Custom Container Layout

```typescript
<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>
```