Dialog
A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
import { Component } from '@angular/core';
import { HlmButtonDirective } from '@spartan-ng/ui-button-helm';
import { BrnDialogContentDirective, BrnDialogTriggerDirective } from '@spartan-ng/ui-dialog-brain';
import {
HlmDialogComponent,
HlmDialogContentComponent,
HlmDialogDescriptionDirective,
HlmDialogFooterComponent,
HlmDialogHeaderComponent,
HlmDialogTitleDirective,
} from '@spartan-ng/ui-dialog-helm';
import { HlmInputDirective } from '@spartan-ng/ui-input-helm';
import { HlmLabelDirective } from '@spartan-ng/ui-label-helm';
@Component({
selector: 'spartan-dialog-preview',
standalone: true,
imports: [
BrnDialogTriggerDirective,
BrnDialogContentDirective,
HlmDialogComponent,
HlmDialogContentComponent,
HlmDialogHeaderComponent,
HlmDialogFooterComponent,
HlmDialogTitleDirective,
HlmDialogDescriptionDirective,
HlmLabelDirective,
HlmInputDirective,
HlmButtonDirective,
],
template: `
<hlm-dialog>
<button id="edit-profile" brnDialogTrigger hlmBtn>Edit Profile</button>
<hlm-dialog-content class="sm:max-w-[425px]" *brnDialogContent="let ctx">
<hlm-dialog-header>
<h3 hlmDialogTitle>Edit profile</h3>
<p hlmDialogDescription>Make changes to your profile here. Click save when you're done.</p>
</hlm-dialog-header>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<label hlmLabel for="name" class="text-right">Name</label>
<input hlmInput id="name" value="Pedro Duarte" class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<label hlmLabel for="username" class="text-right">Username</label>
<input hlmInput id="username" value="@peduarte" class="col-span-3" />
</div>
</div>
<hlm-dialog-footer>
<button hlmBtn type="submit">Save changes</button>
</hlm-dialog-footer>
</hlm-dialog-content>
</hlm-dialog>
`,
})
export class DialogPreviewComponent {}
Installation
npx nx g @spartan-ng/cli:ui dialog
ng g @spartan-ng/cli:ui dialog
Usage
import { BrnDialogContentDirective, BrnDialogTriggerDirective } from '@spartan-ng/ui-dialog-brain';
import {
HlmDialogComponent,
HlmDialogContentComponent,
HlmDialogDescriptionDirective,
HlmDialogFooterComponent,
HlmDialogHeaderComponent,
HlmDialogTitleDirective,
} from '@spartan-ng/ui-dialog-helm';
<hlm-dialog>
<button brnDialogTrigger hlmBtn>Edit Profile</button>
<hlm-dialog-content *brnDialogContent="let ctx">
<hlm-dialog-header>
<h3 brnDialogTitle hlm>Edit profile</h3>
<p brnDialogDescription hlm>Make changes to your profile here. Click save when you're done.</p>
</hlm-dialog-header>
<hlm-dialog-footer>
<button hlmBtn type="submit">Save changes</button>
</hlm-dialog-footer>
</hlm-dialog-content>
</brn-dialog>
Inside Menu
You can nest dialogs inside context or dropdown menus. Make sure to wrap the menu-item inside the brn-dialog
component and apply the BrnDialogTrigger
directive. Another option is to use the brnDialogTriggerFor
alternative, which takes in a reference to the brn-dialog. That way you can avoid nesting the template.
Note
Do not use the HlmMenuItem
or BrnMenuItem
directives as they conflict with BrnDialogTrigger
& brnDialogTriggerFor!
We expose the hlm variants so you can directly use them to style your elements. Check out the code of the example below!
import { Component } from '@angular/core';
import { HlmButtonDirective } from '@spartan-ng/ui-button-helm';
import { BrnDialogContentDirective, BrnDialogTriggerDirective } from '@spartan-ng/ui-dialog-brain';
import {
HlmDialogComponent,
HlmDialogContentComponent,
HlmDialogDescriptionDirective,
HlmDialogFooterComponent,
HlmDialogHeaderComponent,
HlmDialogTitleDirective,
} from '@spartan-ng/ui-dialog-helm';
import { HlmInputDirective } from '@spartan-ng/ui-input-helm';
import { HlmLabelDirective } from '@spartan-ng/ui-label-helm';
import { BrnContextMenuTriggerDirective } from '@spartan-ng/ui-menu-brain';
import {
HlmMenuComponent,
HlmMenuGroupComponent,
HlmMenuItemDirective,
HlmMenuShortcutComponent,
hlmMenuItemVariants,
} from '@spartan-ng/ui-menu-helm';
@Component({
selector: 'spartan-dialog-context-menu',
standalone: true,
imports: [
BrnDialogTriggerDirective,
BrnDialogContentDirective,
HlmDialogContentComponent,
HlmDialogComponent,
HlmDialogHeaderComponent,
HlmDialogFooterComponent,
HlmDialogTitleDirective,
HlmDialogDescriptionDirective,
HlmLabelDirective,
HlmButtonDirective,
HlmInputDirective,
BrnContextMenuTriggerDirective,
HlmMenuItemDirective,
HlmMenuShortcutComponent,
HlmMenuComponent,
HlmMenuGroupComponent,
],
template: `
<div
[brnCtxMenuTriggerFor]="menu"
class="border-border flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm"
>
Right click here
</div>
<ng-template #menu>
<hlm-menu class="w-64">
<hlm-menu-group>
<button inset hlmMenuItem>
Save
<hlm-menu-shortcut>⌘S</hlm-menu-shortcut>
</button>
<button disabled inset hlmMenuItem>
Archive
<hlm-menu-shortcut>⌘A</hlm-menu-shortcut>
</button>
<hlm-dialog>
<button [class]="_hlmMenuItemClasses" brnDialogTrigger>
Print
<hlm-menu-shortcut>⌘P</hlm-menu-shortcut>
</button>
<hlm-dialog-content *brnDialogContent="let ctx">
<hlm-dialog-header>
<h3 brnDialogTitle hlm>Print this page</h3>
<p brnDialogDescription hlm>
Are you sure you want to print this page? Only print if absolutely necessary! The less we print, the
less paper we need, the better it is for our environment!
</p>
</hlm-dialog-header>
<hlm-dialog-footer>
<button hlmBtn variant="ghost" (click)="ctx.close()">Cancel</button>
<button hlmBtn>Print</button>
</hlm-dialog-footer>
</hlm-dialog-content>
</hlm-dialog>
</hlm-menu-group>
</hlm-menu>
</ng-template>
`,
})
export class DialogContextMenuPreviewComponent {
protected readonly _hlmMenuItemClasses = hlmMenuItemVariants({ inset: true });
}
Dynamic Component
You can dynamically open a dialog with a component rendered as the content. The dialog context can be injected into the dynamic component using the provided injectBrnDialogContext
function.
import {
HlmDialogDescriptionDirective,
HlmDialogHeaderComponent,
HlmDialogService,
HlmDialogTitleDirective,
} from '@spartan-ng/ui-dialog-helm';
import { HlmIconComponent, provideIcons } from '@spartan-ng/ui-icon-helm';
import { HlmTableComponent, HlmTdComponent, HlmThComponent, HlmTrowComponent } from '@spartan-ng/ui-table-helm';
type ExampleUser = {
name: string;
email: string;
phone: string;
};
@Component({
selector: 'spartan-dialog-dynamic-component-preview',
standalone: true,
imports: [HlmButtonDirective],
template: `
<button hlmBtn (click)="openDynamicComponent()">Select User</button>
`,
})
export class DialogDynamicComponentPreviewComponent {
private readonly _hlmDialogService = inject(HlmDialogService);
private readonly _users: ExampleUser[] = [
{
name: 'Helena Chambers',
email: 'helenachambers@chorizon.com',
phone: '+1 (812) 588-3759',
},
{
name: 'Josie Crane',
email: 'josiecrane@hinway.com',
phone: '+1 (884) 523-3324',
},
{
name: 'Lou Hartman',
email: 'louhartman@optyk.com',
phone: '+1 (912) 479-3998',
},
{
name: 'Lydia Zimmerman',
email: 'lydiazimmerman@ultrasure.com',
phone: '+1 (944) 511-2111',
},
];
public openDynamicComponent() {
const dialogRef = this._hlmDialogService.open(SelectUserComponent, {
context: {
users: this._users,
},
contentClass: 'sm:!max-w-[750px]',
});
dialogRef.closed$.subscribe((user) => {
if (user) {
console.log('Selected user:', user);
}
});
}
}
@Component({
selector: 'dynamic-content',
standalone: true,
imports: [
HlmDialogHeaderComponent,
HlmDialogTitleDirective,
HlmDialogDescriptionDirective,
HlmTableComponent,
HlmThComponent,
HlmTrowComponent,
HlmTdComponent,
HlmButtonDirective,
HlmIconComponent,
],
providers: [provideIcons({ lucideCheck })],
template: `
<hlm-dialog-header>
<h3 hlmDialogTitle>Select user</h3>
<p hlmDialogDescription>Click a row to select a user.</p>
</hlm-dialog-header>
<hlm-table>
<hlm-trow>
<hlm-th class="w-44">Name</hlm-th>
<hlm-th class="w-60">Email</hlm-th>
<hlm-th class="w-48">Phone</hlm-th>
</hlm-trow>
@for (user of users; track user.name) {
<button class="text-left" (click)="selectUser(user)">
<hlm-trow>
<hlm-td truncate class="w-44 font-medium">{{ user.name }}</hlm-td>
<hlm-td class="w-60">{{ user.email }}</hlm-td>
<hlm-td class="w-48">{{ user.phone }}</hlm-td>
</hlm-trow>
</button>
}
</hlm-table>
`,
})
class SelectUserComponent {
@HostBinding('class') private readonly _class: string = 'flex flex-col gap-4';
private readonly _dialogRef = inject<BrnDialogRef<ExampleUser>>(BrnDialogRef);
private readonly _dialogContext = injectBrnDialogContext<{ users: ExampleUser[] }>();
protected readonly users = this._dialogContext.users;
public selectUser(user: ExampleUser) {
this._dialogRef.close(user);
}
}