Skip to main content

Modal

The Modal component provides an accessible and flexible dialog interface for displaying content on top of the current page. It supports controlled and uncontrolled usage patterns, positioning, sizing, lifecycle callbacks, and backdrop configuration.


Usage

import { Modal } from "@kousta-ui/components";

<Modal modalTrigger="Open Modal">
{/* Modal Content */}
</Modal>

The modal can be controlled internally (uncontrolled) or externally (controlled) via props.


Props

NameTypeDescriptionRequiredDefault
modalTriggerstring | ReactNodeThe element or string that triggers the modal (for uncontrolled modals).No-
openedbooleanControls whether the modal is open (for controlled modals).No-
onCloseVoidFunctionCalled when modal is closed (required for controlled modals).Yes (Controlled)-
titlestring | ReactNodeThe modal title.No-
withCloseBtnbooleanDisplays a close button in the header.Notrue
sizeModalSize | stringSets modal width.No"md"
withBackdropbooleanDisplays a backdrop overlay behind the modal.Notrue
positionModalPositionControls modal position relative to the viewport.No"center"
offsetnumberDistance in pixels from viewport edge (used with top, bottom, etc.).Noundefined
fullHeightbooleanMakes the modal occupy the full viewport height (100vh).Nofalse
fullWidthbooleanMakes the modal occupy the full viewport width (100vw).Nofalse
beforeOpen() => void | booleanExecutes before opening. Returning false cancels opening.No-
afterOpenVoidFunctionExecutes right after modal opens.No-
beforeClose() => void | booleanExecutes before closing. Returning false cancels closing.No-
afterCloseVoidFunctionExecutes right after modal closes.No-

Uncontrolled Modal

An uncontrolled modal manages its open state internally. Use this when the modal is lightweight and doesn’t depend on heavy data or async requests.

info

Use uncontrolled modals for simple UI dialogs such as confirmations or local information.

<Modal modalTrigger="Open Modal">
<p>This is a simple uncontrolled modal.</p>
</Modal>

Preview



When not to use it

Avoid uncontrolled modals for complex or data-heavy components since they mount immediately when the page loads.


Controlled Modal

A controlled modal allows parent components to manage its open/close state manually. This is useful for modals that depend on asynchronous data or need to be programmatically opened/closed.

import { useDisclosure } from "@kousta-ui/hooks";

const Example = () => {
const { close, open, opened } = useDisclosure(false);

return (
<>
<button onClick={open}>Open Modal</button>
<Modal opened={opened} onClose={close} title="Controlled Modal">
<p>This modal is controlled from outside.</p>
</Modal>
</>
);
};

Preview




By combining position and fullHeight, you can create Drawer-like modals anchored to screen edges.

<Modal
modalTrigger="Open Drawer"
position="left-top"
fullHeight
>
<p>This modal behaves like a drawer.</p>
</Modal>

Preview




SizeValueDescription
xs600pxExtra small modal
sm850pxSmall modal
md1250pxMedium (default)
lg1440pxLarge modal
xl1800pxExtra large modal

You can also provide a custom pixel width as a string, e.g. "1000px".


Size, position, and offset

size, position, and offset are implemented via inline styles on the modal container.

Preview (interactive)


PositionDescription
centerCenter of the viewport
topAnchored at the top
bottomAnchored at the bottom
left, rightVertically centered side panels
left-top, left-bottom, right-top, right-bottomCorner positions

Close behaviors

The modal can close on:

  • Escape (default closeOnClickEsc={true})
  • Outside click / touch (default closeOnClickOutside={true})

Disable either behavior explicitly:

import { Modal } from "@kousta-ui/components";
import { useDisclosure } from "@kousta-ui/hooks";

export function Example() {
const { open, close, opened } = useDisclosure(false);

return (
<>
<button onClick={open}>Open</button>
<Modal
opened={opened}
onClose={close}
closeOnClickEsc={false}
closeOnClickOutside={false}
>
<p>Use the close button (X) to close this modal.</p>
</Modal>
</>
);
}

Preview


Lifecycle Callbacks

HookDescriptionUsage
beforeOpenRuns before opening. Return false to prevent opening.Validation or async checks
afterOpenRuns immediately after modal opens.Analytics or focus logic
beforeCloseRuns before closing. Return false to cancel close.Confirm dialogs
afterCloseRuns immediately after modal closes.Cleanup or notifications

Animations Upcoming

Animation support (fade, slide, zoom, etc.) is currently not implemented but is planned for a future release.


Type Definitions

export type ModalSize = "xs" | "sm" | "md" | "lg" | "xl";

export type ModalPosition =
| "top"
| "bottom"
| "right"
| "right-top"
| "right-bottom"
| "left"
| "left-top"
| "left-bottom"
| "center";

export type ModalProps = { /* see props table above */ }

Tips

  • The modal automatically handles body scroll locking.
  • Use withBackdrop={false} for non-blocking overlays.
  • Combine fullWidth and position="bottom" for a mobile sheet effect.

Styles & customization

Runtime classes

  • Modal container
    • kui-modal
    • kui-modal-{size} (example: kui-modal-md)
    • kui-modal-{position} (example: kui-modal-center)
  • Backdrop
    • kui-modal-backdrop
  • Header
    • kui-modal-header
  • Title
    • kui-modal-title
  • Close button
    • kui-modal-close
  • Body
    • kui-modal-body
  • Footer
    • kui-modal-footer

Tokens used by the default styles

  • Colors
    • --kui-neutral-100, --kui-neutral-800, --kui-neutral-950
  • Spacing
    • --kui-spacing-xs, --kui-spacing-sm
  • Typography
    • --kui-text-base
  • Rounding
    • --kui-rounded