Dialog
A dialog is a focused, overlay-based container used to present critical information or request user input that requires immediate attention. It appears above the application content, blocks underlying interaction, and guides the user toward a required decision or acknowledgement.
import {DialogModule} from "@qualcomm-ui/angular/dialog"Examples
Sizes
The dialog component has two sizes: sm and md. Size governs the width of the dialog, as well as the content's spacing, font size, and padding.
<div q-dialog-root size="sm">
<button emphasis="primary" q-button q-dialog-trigger variant="fill">
Open Dialog (sm)
</button>
<dialog-content-demo />
</div>
Indicator Emphasis
Use the emphasis prop to change the intent and color of the dialog's indicator icon.
import {Component} from "@angular/core"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
import type {QdsDialogEmphasis} from "@qualcomm-ui/qds-core/dialog"
@Component({
imports: [DialogModule, ButtonModule],
selector: "dialog-emphasis-demo",
template: `
<div class="flex flex-col gap-4">
@for (color of emphasis; track color) {
<div class="flex justify-center" q-dialog-root [emphasis]="color">
<button q-button q-dialog-trigger size="sm" variant="outline">
{{ color }}
</button>
<q-dialog-floating-portal>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Dialog Title</h2>
<div q-dialog-description>Dialog Description</div>
</div>
<div q-dialog-footer>
<button q-button q-dialog-close-trigger size="sm" variant="fill">
Close
</button>
</div>
</q-dialog-floating-portal>
</div>
}
</div>
`,
})
export class DialogEmphasisDemo {
readonly emphasis: QdsDialogEmphasis[] = [
"neutral",
"info",
"success",
"warning",
"danger",
]
}Custom Indicator
Set a custom indicator icon by providing the q-dialog-indicator-icon directive within the q-dialog-body directive. Or hide it entirely using the hideIndicatorIcon property on the q-dialog-body directive.
<div q-dialog-body>
<svg q-dialog-indicator-icon qIcon="AArrowDown"></svg>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Dialog Title</h2>
<div q-dialog-description>Dialog Description</div>
</div>
Placement
Use the placement prop to change the placement of the dialog.
import {Component} from "@angular/core"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
import type {QdsDialogPlacement} from "@qualcomm-ui/qds-core/dialog"
@Component({
imports: [DialogModule, ButtonModule],
selector: "dialog-placement-demo",
template: `
<div class="flex flex-col gap-4">
@for (placement of placements; track placement) {
<div class="flex justify-center" q-dialog-root [placement]="placement">
<button q-button q-dialog-trigger size="sm" variant="outline">
Open Dialog ({{ placement }})
</button>
<q-dialog-floating-portal>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Dialog Title</h2>
<div q-dialog-description>Dialog Description</div>
</div>
<div q-dialog-footer>
<button q-button q-dialog-close-trigger size="sm" variant="fill">
Close
</button>
</div>
</q-dialog-floating-portal>
</div>
}
</div>
`,
})
export class DialogPlacementDemo {
placements: QdsDialogPlacement[] = ["top", "center", "bottom"]
}Controlled State
Dialog visibility can be controlled using the open, openChanged and defaultOpen properties. These properties follow our controlled state pattern.
import {Component, signal} from "@angular/core"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
@Component({
imports: [DialogModule, ButtonModule],
selector: "dialog-controlled-state-demo",
template: `
<div q-dialog-root [open]="open()" (openChanged)="onOpenChange($event)">
<button emphasis="primary" q-button q-dialog-trigger variant="fill">
Open Dialog
</button>
<q-dialog-floating-portal>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Dialog Title</h2>
<div q-dialog-description>Dialog Description</div>
</div>
<div q-dialog-footer>
<button q-button q-dialog-close-trigger size="sm" variant="fill">
Close
</button>
</div>
</q-dialog-floating-portal>
</div>
`,
})
export class DialogControlledStateDemo {
readonly open = signal(false)
onOpenChange(open: boolean) {
console.debug("Dialog open changed:", open)
this.open.set(open)
}
}Outside Scroll
The default scrollBehavior is outside, which makes the entire page scrollable when modal content exceeds viewport height. The modal and backdrop move with the page scroll instead of creating an internal scroll area within the modal.
import {Component} from "@angular/core"
import {LoremIpsumDirective} from "@qualcomm-ui/angular-core/lorem-ipsum"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
@Component({
imports: [DialogModule, ButtonModule, LoremIpsumDirective],
selector: "dialog-outside-scroll-demo",
template: `
<div q-dialog-root>
<button emphasis="primary" q-button q-dialog-trigger variant="fill">
Open Dialog
</button>
<q-dialog-floating-portal>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Dialog Title</h2>
<div q-dialog-description>
<div numParagraphs="20" q-lorem-ipsum></div>
</div>
</div>
<div q-dialog-footer>
<button q-button q-dialog-close-trigger size="sm" variant="fill">
Close
</button>
</div>
</q-dialog-floating-portal>
</div>
`,
})
export class DialogOutsideScrollDemo {}Inside Scroll
Set the scrollBehavior prop to inside to create an internal scroll area within the modal.
import {Component} from "@angular/core"
import {LoremIpsumDirective} from "@qualcomm-ui/angular-core/lorem-ipsum"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
@Component({
imports: [DialogModule, ButtonModule, LoremIpsumDirective],
selector: "dialog-inside-scroll-demo",
template: `
<div q-dialog-root scrollBehavior="inside">
<button emphasis="primary" q-button q-dialog-trigger variant="fill">
Open Dialog
</button>
<q-dialog-floating-portal>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Dialog Title</h2>
<div q-dialog-description>
<div numParagraphs="20" q-lorem-ipsum></div>
</div>
</div>
<div q-dialog-footer>
<button q-button q-dialog-close-trigger size="sm" variant="outline">
Close
</button>
<button
emphasis="primary"
q-button
q-dialog-close-trigger
size="sm"
variant="fill"
>
Confirm
</button>
</div>
</q-dialog-floating-portal>
</div>
`,
})
export class DialogInsideScrollDemo {}Alert Dialog
Set the role prop to alertdialog to change the dialog component to an alert dialog. This is recommended for situations where the dialog is used to notify users of urgent information that demands their immediate attention.
import {Component} from "@angular/core"
import {Trash2} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
@Component({
imports: [DialogModule, ButtonModule],
providers: [provideIcons({Trash2})],
selector: "dialog-alert-dialog-demo",
template: `
<div emphasis="danger" q-dialog-root role="alertdialog">
<button
emphasis="danger"
endIcon="Trash2"
q-button
q-dialog-trigger
variant="outline"
>
Delete Account
</button>
<q-dialog-floating-portal>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h2 q-dialog-heading>Are you sure?</h2>
<div q-dialog-description>
This action cannot be undone. This will permanently delete your
account and remove your data from our systems.
</div>
</div>
<div q-dialog-footer>
<button q-button q-dialog-close-trigger size="sm" variant="outline">
Cancel
</button>
<button
emphasis="danger"
q-button
q-dialog-close-trigger
size="sm"
variant="fill"
>
Confirm
</button>
</div>
</q-dialog-floating-portal>
</div>
`,
})
export class DialogAlertDialogDemo {}Shortcuts
<q-dialog-floating-portal>
A helper component that combines the portal, positioner, and content components. This shortcut is equivalent to:
<q-portal>
<div q-dialog-backdrop></div>
<div q-dialog-positioner>
<section q-dialog-content><ng-content /></section>
</div>
</q-portal>API
<q-dialog-root>
stringbooleanbooleanboolean'ltr' | 'rtl'
| 'info'
| 'success'
| 'warning'
| 'danger'
| 'neutral'
() => HTMLElement
() =>
| Node
| ShadowRoot
| Document
boolean() => HTMLElement
booleanbooleanbooleanArray<
() => Element
>
- should not have pointer-events disabled
- should not trigger the dismiss event
| 'top'
| 'center'
| 'bottom'
booleanbooleanboolean| 'dialog'
| 'alertdialog'
| 'inside'
| 'outside'
'sm' | 'md'
booleanbooleanbooleanKeyboardEventvoidCustomEvent<{
event?: E
}>
| CustomEvent<{event?: E}>
| CustomEvent<{event?: E}>
booleanCustomEvent<{
event?: E
}>
CustomEvent<{
originalIndex: number
originalLayer: HTMLElement
targetIndex: number
targetLayer: HTMLElement
}>
<q-dialog-floating-portal>
q-dialog-backdrop
class'qui-dialog__backdrop'data-dialog-part'backdrop'data-state| 'open'
| 'closed'
hiddenbooleanq-dialog-positioner
stringclass'qui-dialog__positioner'data-dialog-part'positioner'data-placement| 'top'
| 'center'
| 'bottom'
data-scroll-behavior| 'inside'
| 'outside'
data-size'sm' | 'md'
styleq-dialog-content
stringclass'qui-dialog__content'data-dialog-part'content'data-scroll-behavior| 'inside'
| 'outside'
data-size'sm' | 'md'
data-state| 'open'
| 'closed'
hiddenbooleantabIndex-1
q-dialog-body
booleanclass'qui-dialog__body'data-dialog-part'body'data-size'sm' | 'md'
q-dialog-heading
stringclass'qui-dialog__heading'data-dialog-part'heading'data-size'sm' | 'md'
q-dialog-footer
class'qui-dialog__footer'data-dialog-part'footer'data-size'sm' | 'md'
q-dialog-indicator-icon
class'qui-dialog__indicator-icon'data-emphasis| 'info'
| 'success'
| 'warning'
| 'danger'
| 'neutral'
data-size'sm' | 'md'
q-dialog-close-button
stringclass'qui-dialog__close-button'data-dialog-part'close-trigger'