AhaSlides Design
v0.52.0React · Vue · Lit

Components · Feedback

Modal

A focused, blocking dialog in two types — a Confirmation (yes/no decision) and an Action (a task surface) — rendered through the shared Modal.

Examples

API

PropTypeDefaultNotes
openbooleanfalseControls visibility
titlestringDialog heading
onOk() => voidConfirm handler
onCancel() => voidDismiss handler
confirmLoadingbooleanfalseSpinner on the confirm button
widthstringmodalWidth('simple')Dialog width — pass modalWidth(size): min(target px, calc(100vw − 32px)) so it's the px width on desktop and near-full-width on mobile. Targets: simple 504 / complexity 720 / rich 1280
stylesobjectmodalStyles('simple')Height cap + body scroll for the size — modalStyles(size)
footerReactNodeDS footer: Learn-more link (left, a --aha-text-link anchor — external-link glyph only when it leaves AhaSlides) + Cancel + Apply (right)
centeredbooleanfalseVertically centre the dialog in the viewport
closablebooleantrueShow the top-right close (X)
maskbooleantrueRender the dimming overlay behind the dialog

Install

# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}   # a GitHub token with read:packages

npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css';   // once, at the app root
import '@ahaslides-product/design/modal-theme';   // registers <modal>

Agent feed for this component (absolute, fetchable anywhere): modal.agent.json · modal.md · modal.llms.txt

When to use

When to use
  • Modal — the user must confirm or complete a focused task before continuing
  • Drawer — a longer edit form or detail panel that keeps page context
  • Popconfirm — a lightweight yes/no on a single control
Two types. A CONFIRMATION modal is a focused yes/no — one of five contexts (default · confirm · warning · info · danger) puts a status icon left of the title, with a short line of copy, a Learn-more link, and Cancel + Apply; it's always `simple` size. An ACTION modal is a task surface (form, picker, editor) at one of three sizes — simple / complexity / rich — with an optional header/footer divider. Both are controlled `<Modal>`s, never the static Modal.confirm(). Every modal opens as a real overlay: it portals to `<body>` with an always-on mask, locks page scroll while open, and closes on a mask click / Esc / the ✕ — EXCEPT a destructive confirmation, which overrides `mask={{ closable: false }}` so a stray backdrop click can't trigger the action (Esc + ✕ only). Name the primary button the action ('Delete team', not 'OK'). A modal must never grow bigger than the screen in either axis: set `width={modalWidth(size)}` (resolves to `min(<target px>, calc(100vw − 32px))` — the px width on desktop, near-full-width on mobile with a 16px gutter; antd centres the dialog by its width, so the cap lives on the prop, not inner styles) and `styles={modalStyles(size)}` (height `auto` up to the cap, then the body scrolls while title + footer stay pinned). Anything bigger than `rich` belongs in its own page.
Surfaces
editor dashboard settings

Spec

Content white surface · radius 8 · Title ink #1A1A1A · 18 · SemiBold · Footer brand primary confirm + secondary cancel · Overlay always-on mask (ink rgba(26,26,46,.7)) · portals to body · locks page scroll · click mask / Esc / ✕ to close (destructive: mask not closable) · Motion antd's built-in zoom enter/leave (kept) · Types Confirmation (status icon + copy) · Action (task surface) · Confirmation contexts: default · confirm · warning · info · danger (status icon left of title) · Action sizes simple 504 · complexity 720 · rich 1280 (px width) × height 75/80/90vh · divider on/off · Viewport cap width={modalWidth(size)} = min(px, calc(100vw − 32px)) — px on desktop, near-full-width on mobile; styles={modalStyles(size)} caps height, body scrolls past it