Modal Dialog
Use when the user needs to confirm an action, acknowledge a warning, or complete a short form before the app can continue
Built-in Features
Modals wire up from data-modal-target and data-modal-close attributes with no JavaScript init call required.
Tab and Shift+Tab cycle through focusable elements inside the modal, keeping keyboard users contained until they dismiss it.
Pressing Escape closes the modal and its backdrop without any extra wiring.
A dimmed, blurred overlay covers the page behind the modal. Clicking the backdrop closes the modal automatically.
Page scrolling is disabled while a modal is open and restored when it closes.
On small screens the modal slides up from the bottom with rounded top corners, and action buttons expand to full width.
Fade and scale on desktop, slide on mobile. The closing state drives the exit animation automatically.
Open, close, and check state with NDS.Modal.open(), NDS.Modal.close(), and NDS.Modal.isOpen().
Usage Guidelines
Best Practices
- Use a modal when the user must confirm or decide something before the app can continue, such as approving a submission or accepting terms
- Use for presenting critical warnings, compliance notices, or destructive action confirmations where the user must acknowledge before proceeding
- Use for short forms or detail views that benefit from focused attention without navigating away from the current page
- Don't use for success messages or non-blocking notifications. Use an Alert or Toast instead
- For multi-step workflows inside a modal, use the Stepper component to guide users through each stage. For workflows too complex for a modal, use a dedicated page instead
- Don't stack modals. If one modal needs to open another, restructure the flow so a single modal handles the decision
- Menu-based controls work inside a modal with no extra attribute: a Dropmenu, a select, a Multiselect, an Autocomplete, or a Filter. The modal card scrolls its own content and creates a stacking context, so each menu detects the modal on open and moves to
<body>instead of clipping at the card edge. A menu taller than the space on either side of its trigger scrolls inside the viewport. Older markup that carriesdata-portalon the.nds-dropmenuwrapper still works — the attribute forces the same move - Choose
nds-smfor simple confirmation prompts with one or two buttons. Use the default size when the modal includes a short form or longer description. Usends-lgfor content-heavy modals like terms of service or data previews. Usends-fullfor immersive tasks like image editing or document previews - To keep a modal out of the DOM until first open, wrap it in
<template class="nds-modal-template">. The trigger stays outside the template. The markup joins the page on the first click. One modal per template. Do not wrap a modal that holds content people should find with page search — content inside a template is invisible to search engines and Ctrl+F. Page scripts must not look the modal up at load: the element is not in the page yet. Listen ondocumentfornds:template:readyinstead. NDS fires it on the modal after the markup joins the page and its components are wired - Keep titles clear and contextual to the required action
- Limit content to a single focused message or task
- Provide explicit primary and secondary actions (Confirm/Cancel)
Modifier Classes
| Class | Description |
|---|---|
nds-sm |
Small modal, max-width 400px. Use for simple confirmation dialogs. |
nds-md |
Medium modal, max-width 600px. This is the default size when no class is added. |
nds-lg |
Large modal, max-width 800px. Use for content-heavy dialogs. |
nds-full |
Full-width modal with minimal side margins. Use for immersive tasks. |
nds-modal-template |
Set on a <template> that wraps the modal. The modal joins the DOM on first open instead of loading with the page. See Best Practices for the rules. |
Data Attributes
| Attribute | Description |
|---|---|
data-modal-target="id" |
Set on a trigger button. Opens the modal with the matching id when clicked. |
data-modal-close |
Set on any element inside a modal. Closes the currently open modal when clicked. |
data-modal-static |
Set on the modal. Removes both dismiss paths: no Esc key, no backdrop click. The modal then closes only through a data-modal-close control or NDS.Modal.close(). Use it when the user must pick one of the actions. |
data-state="open|closing" |
Set on the modal by JavaScript. open while the modal is shown, closing during the close animation, and removed once it is closed. Style off it. Do not set it by hand. |
JavaScript API
NDS.Modal initializes automatically on page load. The modal script depends on nds-backdrop.js, which must load first.