Command
Fast, composable, command menu for Angular.
import { Component } from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
lucideCalculator,
lucideCalendar,
lucideCog,
lucidePlus,
lucideSearch,
lucideSmile,
lucideUser,
lucideWallet,
} from '@ng-icons/lucide';
import { BrnCommandImports } from '@spartan-ng/brain/command';
import { HlmCommandImports } from '@spartan-ng/helm/command';
import { HlmIcon } from '@spartan-ng/helm/icon';
@Component({
selector: 'spartan-command-preview',
imports: [BrnCommandImports, HlmCommandImports, NgIcon, HlmIcon],
providers: [
provideIcons({
lucideSearch,
lucideCalendar,
lucideSmile,
lucidePlus,
lucideUser,
lucideWallet,
lucideCog,
lucideCalculator,
}),
],
template: `
<hlm-command class="rounded-lg border shadow-md md:min-w-[450px]">
<hlm-command-search>
<ng-icon hlm name="lucideSearch" class="shrink-0 opacity-50" />
<input type="text" hlm-command-search-input placeholder="Type a command or search..." />
</hlm-command-search>
<hlm-command-list>
<hlm-command-group>
<hlm-command-group-label>Suggestions</hlm-command-group-label>
<button hlm-command-item value="Calendar">
<ng-icon hlm name="lucideCalendar" hlmCommandIcon />
Calendar
</button>
<button hlm-command-item value="Search Emoji">
<ng-icon hlm name="lucideSmile" hlmCommandIcon />
Search Emoji
</button>
<button hlm-command-item value="Calculator" disabled>
<ng-icon hlm name="lucideCalculator" hlmCommandIcon />
Calculator
</button>
</hlm-command-group>
<hlm-command-separator />
<hlm-command-group>
<hlm-command-group-label>Settings</hlm-command-group-label>
<button hlm-command-item value="Profile">
<ng-icon hlm name="lucideUser" hlmCommandIcon />
Profile
<hlm-command-shortcut>⌘P</hlm-command-shortcut>
</button>
<button hlm-command-item value="Billing">
<ng-icon hlm name="lucideWallet" hlmCommandIcon />
Billing
<hlm-command-shortcut>⌘B</hlm-command-shortcut>
</button>
<button hlm-command-item value="Settings">
<ng-icon hlm name="lucideCog" hlmCommandIcon />
Settings
<hlm-command-shortcut>⌘S</hlm-command-shortcut>
</button>
</hlm-command-group>
</hlm-command-list>
<!-- Empty state -->
<div *brnCommandEmpty hlmCommandEmpty>No results found.</div>
</hlm-command>
`,
})
export class CommandPreview {}
Installation
npx nx g @spartan-ng/cli:ui command
ng g @spartan-ng/cli:ui command
Usage
import { BrnCommandImports } from '@spartan-ng/brain/command';
import { HlmCommandImports } from '@spartan-ng/helm/command';
<hlm-command>
<hlm-command-search>
<ng-icon hlm name="lucideSearch" />
<input
type="text"
hlm-command-search-input
placeholder="Type a command or search..."
/>
</hlm-command-search>
<hlm-command-list>
<hlm-command-group>
<hlm-command-group-label>Suggestions</hlm-command-group-label>
<button hlm-command-item value="Calendar">
<ng-icon hlm name="lucideCalendar" hlmCommandIcon />
Calendar
</button>
</hlm-command-group>
<hlm-command-separator />
<hlm-command-group>
<hlm-command-group-label>Settings</hlm-command-group-label>
<button hlm-command-item value="Profile">
<ng-icon hlm name="lucideUser" hlmCommandIcon />
Profile
<hlm-command-shortcut>⌘P</hlm-command-shortcut>
</button>
</hlm-command-group>
</hlm-command-list>
<!-- Empty state -->
<div *brnCommandEmpty hlmCommandEmpty>No results found.</div>
</hlm-command>
Brain API
BrnCommandEmpty
Selector: [brnCommandEmpty]
BrnCommandGroup
Selector: [brnCommandGroup]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | string | `brn-command-group-${BrnCommandGroup._id++}` | The id of the command list |
BrnCommandItem
Selector: button[brnCommandItem]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | unknown | `brn-command-item-${BrnCommandItem._id++}` | A unique id for the item |
value* (required) | string | - | The value this item represents. |
disabled | boolean | false | Whether the item is disabled. |
Outputs
Prop | Type | Default | Description |
---|---|---|---|
selected | void | - | Emits when the item is selected. |
BrnCommandList
Selector: [brnCommandList]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | string | `brn-command-list-${BrnCommandList._id++}` | The id of the command list |
BrnCommandSearchInput
Selector: input[brnCommandSearchInput]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
value | string | - | The initial value of the search input |
BrnCommand
Selector: [brnCommand]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
id | string | `brn-command-${BrnCommand._id++}` | The id of the command |
filter | CommandFilter | this._defaultFilter | A custom filter function to use when searching. |
Outputs
Prop | Type | Default | Description |
---|---|---|---|
valueChange | string | - | when the selection has changed |
Helm API
HlmCommandDialogCloseButton
Selector: [hlmCommandDialogCloseBtn]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmCommandDialog
Selector: [hlmCommandDialog]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmCommandEmpty
Selector: [hlmCommandEmpty]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmCommandGroupLabel
Selector: hlm-command-group-label
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | * The user defined class |
HlmCommandGroup
Selector: hlm-command-group
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | * The user defined class |
HlmCommandIcon
Selector: [hlmCommandIcon]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmCommandItem
Selector: button[hlm-command-item]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
value | string | - | The value this item represents. |
disabled | boolean | false | Whether the item is disabled. |
class | string | - | * The user defined class |
Outputs
Prop | Type | Default | Description |
---|---|---|---|
selected | void | - | Emits when the item is selected. |
HlmCommandList
Selector: hlm-command-list
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | The user defined class |
HlmCommandSearchInput
Selector: input[hlm-command-search-input]
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | * The user defined class |
HlmCommandSearch
Selector: hlm-command-search
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | * The user defined class |
HlmCommandSeparator
Selector: hlm-command-separator
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | string | - | * The user defined class |
HlmCommandShortcut
Selector: hlm-command-shortcut
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmCommand
Selector: hlm-command
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | * The user defined class |
Examples
Dialog
Press ⌘ + Shift + P
Last command: none
import { Component, signal } from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
lucideCalendar,
lucideCog,
lucideLayers,
lucidePlus,
lucideSearch,
lucideSmile,
lucideUser,
lucideX,
} from '@ng-icons/lucide';
import { BrnCommandImports } from '@spartan-ng/brain/command';
import { BrnDialog, BrnDialogClose, BrnDialogContent, BrnDialogOverlay } from '@spartan-ng/brain/dialog';
import { HlmButton } from '@spartan-ng/helm/button';
import { HlmCommandImports } from '@spartan-ng/helm/command';
import { HlmDialogOverlay } from '@spartan-ng/helm/dialog';
import { HlmIcon } from '@spartan-ng/helm/icon';
import { HlmCode } from '@spartan-ng/helm/typography';
@Component({
selector: 'spartan-command-dialog',
providers: [
provideIcons({
lucideX,
lucideCalendar,
lucideSmile,
lucidePlus,
lucideUser,
lucideLayers,
lucideCog,
lucideSearch,
}),
],
imports: [
BrnCommandImports,
HlmCommandImports,
NgIcon,
HlmIcon,
HlmButton,
BrnDialog,
BrnDialogClose,
BrnDialogContent,
BrnDialogOverlay,
HlmDialogOverlay,
HlmCode,
],
template: `
<div class="mx-auto flex max-w-screen-sm items-center justify-center space-x-4 py-20 text-sm">
<p>
Press
<code hlmCode>⌘ + Shift + P</code>
</p>
<p>
Last command:
<code data-testid="lastCommand" hlmCode>{{ command() || 'none' }}</code>
</p>
</div>
<brn-dialog [state]="state()" (stateChanged)="stateChanged($event)">
<brn-dialog-overlay hlm />
<hlm-command *brnDialogContent="let ctx" hlmCommandDialog class="mx-auto sm:w-[400px]">
<hlm-command-search>
<ng-icon hlm name="lucideSearch" />
<input placeholder="Type a command or search..." hlm-command-search-input />
<button hlmCommandDialogCloseBtn>
<ng-icon hlm name="lucideX" />
</button>
</hlm-command-search>
<div *brnCommandEmpty hlmCommandEmpty>No results found.</div>
<hlm-command-list hlm>
<hlm-command-group label="Suggestions">
<button hlm-command-item value="calendar" (selected)="commandSelected('calendar')">
<ng-icon hlm name="lucideCalendar" hlmCommandIcon />
Calendar
</button>
<button hlm-command-item value="emojy" (selected)="commandSelected('emojy')">
<ng-icon hlm name="lucideSmile" hlmCommandIcon />
Search Emoji
</button>
<button hlm-command-item value="calculator" (selected)="commandSelected('calculator')">
<ng-icon hlm name="lucidePlus" hlmCommandIcon />
Calculator
</button>
</hlm-command-group>
<hlm-command-separator hlm />
<hlm-command-group hlm label="Settings">
<button hlm-command-item value="profile" (selected)="commandSelected('profile')">
<ng-icon hlm name="lucideUser" hlmCommandIcon />
Profile
<hlm-command-shortcut>⌘P</hlm-command-shortcut>
</button>
<button hlm-command-item value="billing" (selected)="commandSelected('billing')">
<ng-icon hlm name="lucideLayers" hlmCommandIcon />
Billing
<hlm-command-shortcut>⌘B</hlm-command-shortcut>
</button>
<button hlm-command-item value="settings" (selected)="commandSelected('settings')">
<ng-icon hlm name="lucideCog" hlmCommandIcon />
Settings
<hlm-command-shortcut>⌘S</hlm-command-shortcut>
</button>
</hlm-command-group>
</hlm-command-list>
</hlm-command>
</brn-dialog>
`,
host: {
'(window:keydown)': 'onKeyDown($event)',
},
})
export class CommandDialog {
public command = signal('');
public state = signal<'closed' | 'open'>('closed');
onKeyDown(event: KeyboardEvent) {
if ((event.metaKey || event.ctrlKey) && event.shiftKey && (event.key === 'p' || event.key === 'P')) {
this.state.set('open');
}
}
stateChanged(state: 'open' | 'closed') {
this.state.set(state);
}
commandSelected(selected: string) {
this.state.set('closed');
this.command.set(selected);
}
}
Combobox
You can use the brn-command
component as a combobox. See the Combobox page for more information.