# ASModal

`ASModal` renders a controlled overlay into `document.body`. The parent supplies `isOpen` and decides when to close it. Children retain their React context, including the ASUI theme, through the portal.

## Usage

```tsx
import { useState } from 'react';
import { ASButton, ASModal } from '@eleventheye/asui';

const ModalExample = () => {
  const [open, setOpen] = useState(false);
  const handleOpen = () => setOpen(true);
  const handleClose = () => setOpen(false);

  return (
    <>
      <ASButton as="button" onClick={handleOpen}>Open details</ASButton>
      <ASModal isOpen={open} onBackdropClick={handleClose}>
        <h2>Details</h2>
        <ASButton as="button" onClick={handleClose}>Close</ASButton>
      </ASModal>
    </>
  );
};
```

The heading and close button in this example are consumer-supplied content, not built-in parts of `ASModal`. Configure their sizes and styles directly on those components.

## Props and behavior

| Prop | Purpose | Default |
| --- | --- | --- |
| `isOpen` | Mount the backdrop and content portal. | `false` |
| `onBackdropClick` | Handle a backdrop tap. Closing remains the parent's responsibility. | No action |
| `showBackdrop` | Paint the backdrop background. Setting `false` leaves the transparent click surface present. | `true` |
| `theme` | Complete theme replacement for the modal and ASUI descendants. | Inherited theme |
| `themeOverrides` | Partial changes to the inherited theme. Do not combine with `theme`. | None |
| `className` | Class applied to the content wrapper. | Empty |
| `styleOptions.$wrapperOptions` | Local wrapper layout and appearance. | See below |

The wrapper is centered with fixed positioning and defaults to 300px wide and 500px high. Set `$width`, `$height`, `$position`, and `$margin` in `$wrapperOptions` for your layout. `$padding`, `$borderRadius`, and `$backdropFilter` override the corresponding theme values. The theme's `components.modal.innerBorderShadow` controls the decorative inset border; use `'none'` to hide it.

Only explicitly supplied wrapper values override the theme. Omitted wrapper values inherit the theme or default layout, including when `styleOptions` or `$wrapperOptions` is empty. Clearing `styleOptions` to `null` in Storybook is also treated as no override. Prefer `themeOverrides` for appearance-only customization.

The component hides body overflow while open and clears that inline overflow value on close or unmount. It does not coordinate scroll locking between multiple open modals. Closing unmounts the portal immediately; transition styles apply to entry, not a delayed exit lifecycle.

`$showInnerBorder` is deprecated and has no effect, including when set to `false`. Remove it from wrapper options and use `components.modal.innerBorderShadow` instead. Classic themes show the border by default; neutral themes default to `'none'`.

## Theme customization

Configure `components.modal` through `createASTheme` for project-wide styling, or use a local override:

```tsx
<ASModal
  isOpen={open}
  onBackdropClick={handleClose}
  themeOverrides={{
    components: {
      modal: {
        background: 'var(--dialog-surface, #ffffff)',
        outline: '1px solid #667085',
        radius: '12px',
        padding: '24px',
        shadow: '0 8px 32px #0003',
        innerBorderShadow: 'none',
      },
    },
  }}
>
  {children}
</ASModal>
```

Surface and border colors derive from project tokens. Classic styling retains its original appearance until relevant tokens or component slots are explicitly overridden. Modal corners are independent of the shared control radius, so rounded buttons do not make the dialog pill-shaped. Reduced-motion preferences disable backdrop and surface transitions.

See [modal theme properties](./theme-reference.md#asmodal) for all slots and defaults. Variables referenced by portaled styles must be available on an ancestor of the portal container, normally `:root` or `body`; see [Applying an ASUI theme](./theme-provider.md#css-custom-properties-and-portals).

## Accessibility responsibilities

`ASModal` supplies the overlay and portal, not a complete accessible dialog interaction model. It does not assign a dialog role or accessible name, trap or restore focus, close on Escape, or make the rest of the document inert. The consumer must provide those behaviors when presenting a modal dialog. Backdrop tapping must not be the only way to close it; include a keyboard-accessible close control.
