Command
A fast, keyboard-navigable command palette with search filtering, item grouping, and modal dialog support.
import { Command, CommandItem } from "@glint/components/command.slint";import { Tokens } from "@glint/theme/tokens.slint";import { IconSet } from "@lucide";
export component Demo inherits Window { width: 560px; height: 360px; background: Tokens.color-background;
in-out property <string> query: ""; in-out property <string> chosen: "None";
VerticalLayout { alignment: center; spacing: 12px; padding: 20px;
HorizontalLayout { alignment: center;
Command { query <=> root.query; items: [ { id: "new-file", label: "New File", icon: IconSet.FilePlus, hint: "Ctrl+N" }, { id: "open", label: "Open File…", icon: IconSet.FolderOpen, hint: "Ctrl+O" }, { id: "docs", label: "Documentation", icon: IconSet.BookOpen, separator-before: true, heading-before: "Help" }, { id: "settings", label: "Settings", icon: IconSet.Settings, hint: "Ctrl+," }, ]; selected(id) => { root.chosen = id; } } }
Text { text: "Executed command: " + root.chosen; color: Tokens.color-muted-foreground; font-size: Tokens.typography-body-sm-size; horizontal-alignment: center; } }}Usage
import { Command, CommandItem } from "@glint/components/command.slint";
export component AppWindow inherits Window { in-out property <string> search-text;
VerticalLayout { alignment: center;
Command { query <=> root.search-text; items: [ { id: "settings", label: "Settings", hint: "Preferences" }, { id: "profile", label: "Profile", hint: "Account" }, ]; selected(id) => { // handle command } } }}Command provides an inline searchable palette holding a text input over a scrollable list of command options.
The search query is two-way (query <=> ...), allowing the host application to filter items dynamically.
Pressing ↑/↓ navigates the highlight, Home/End jumps to list ends,
Enter runs the selected command firing selected(id), and Escape fires dismissed().
For full-window modal invocation (such as ⌘K / Ctrl+K), use CommandDialog.
Examples
Modal command palette with CommandDialog
CommandDialog wraps the command palette in a full-window modal overlay complete with backdrop scrim, focus trap (FocusSentinel), and accessible focus restoration (restore-focus).
import { Button } from "@glint/components/button.slint";import { CommandDialog } from "@glint/components/command.slint";import { Tokens } from "@glint/theme/tokens.slint";import { IconSet } from "@lucide";
export component Demo inherits Window { width: 560px; height: 360px; background: Tokens.color-background;
in-out property <string> status: "Press button or open palette";
VerticalLayout { alignment: center; spacing: 16px; padding: 24px;
HorizontalLayout { alignment: center;
trigger := Button { text: "Open Command Palette (Ctrl+K)"; haspopup: true; clicked => { cmd.open = true; } } }
Text { text: root.status; color: Tokens.color-muted-foreground; font-size: Tokens.typography-body-sm-size; horizontal-alignment: center; } }
cmd := CommandDialog { width: parent.width; height: parent.height; placeholder: "Type a command…"; items: [ { id: "new-file", label: "Create New Project", icon: IconSet.FolderPlus }, { id: "git-pull", label: "Git: Pull Latest Changes", icon: IconSet.GitPullRequest, separator-before: true, heading-before: "Version Control" }, { id: "git-push", label: "Git: Push Commits", icon: IconSet.UploadCloud }, { id: "help", label: "Keyboard Shortcuts Reference", icon: IconSet.HelpCircle, separator-before: true, heading-before: "General" }, ]; selected(id) => { root.status = "Ran command: " + id; } restore-focus => { trigger.focus(); } }}Grouped commands with hints and icons
Following Glint’s grouped rows model, commands can be organized into categories using separator-before and heading-before without distorting command indexing. Trailing text hints provide category badges or shortcut keys.
import { Command } from "@glint/components/command.slint";import { Tokens } from "@glint/theme/tokens.slint";import { IconSet } from "@lucide";
export component Demo inherits Window { width: 560px; height: 360px; background: Tokens.color-background;
VerticalLayout { alignment: center; padding: 20px;
HorizontalLayout { alignment: center;
Command { items: [ { id: "calc", label: "Calculator", icon: IconSet.Calculator, hint: "App" }, { id: "calendar", label: "Calendar", icon: IconSet.Calendar, hint: "App" }, { id: "dark-theme", label: "Toggle Dark Theme", icon: IconSet.Moon, separator-before: true, heading-before: "Appearance", hint: "System" }, { id: "high-contrast", label: "High Contrast Mode", icon: IconSet.SunMedium, hint: "Accessibility" }, ]; } } }}Zero results empty state
When filtering produces an empty array of items, Command displays an Empty state carrying empty-text rather than collapsing into a blank surface.
import { Command } from "@glint/components/command.slint";import { Tokens } from "@glint/theme/tokens.slint";
export component Demo inherits Window { width: 560px; height: 280px; background: Tokens.color-background;
VerticalLayout { alignment: center; padding: 20px;
HorizontalLayout { alignment: center;
Command { query: "xyznonexistent"; items: []; empty-text: "No commands match your search."; } } }}API Reference
Properties
| Property | Type | Default | Description |
|---|---|---|---|
items | in [CommandItem] | no default | Commands shown in the palette. Each id is what selected fires with. |
query | in-out string | no default | Two-way; current search text. |
highlighted-index | in-out int | 0 | Row that Enter runs; consumers rarely set this directly. |
placeholder | in string | @tr("Type a command or search…") | Hint shown in the search field when empty. |
empty-text | in string | @tr("No results found.") | Shown in place of the list when items is empty — the state a search palette lands in most often. Set it to "" to show nothing at all. |
max-visible-items | in int | 8 | The list shows at most this many rows before it starts scrolling. |
auto-focus | in bool | false | Whether the search field takes the keyboard as soon as the palette is built. Off inline, where the palette is one thing on a page among many; CommandDialog turns it on for a palette that opens with the window. |
Callbacks
| Callback | Description |
|---|---|
selected(string) | Fired with the chosen command's id. |
dismissed() | Fired on Escape. The inline surface reports it rather than acting on it: what a dismissal means belongs to whatever hosts the palette. |
Functions
| Function | Description |
|---|---|
take-focus() | Puts the keyboard in the search field. |
release-focus() | Gives it up again. Taking it first is what makes this work from anywhere: clear-focus() only speaks for the scope that holds it. |
CommandDialog
The full-window modal version of the command palette with backdrop scrim, keyboard trap, and accessible landmark regions.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
open | in-out bool | false | Two-way; consumer sets true to open, Glint sets false on dismissal. |
items | in [CommandItem] | no default | Commands shown in the palette. Each id is what selected fires with. |
query | in-out string | no default | Two-way; current search text. |
highlighted-index | in-out int | 0 | Row that Enter runs; consumers rarely set this directly. |
placeholder | in string | @tr("Type a command or search…") | Hint shown in the search field when empty. |
empty-text | in string | @tr("No results found.") | Shown in place of the list when items is empty. |
max-visible-items | in int | 8 | The list shows at most this many rows before it starts scrolling. |
label | in string | @tr("Command palette") | What the open palette announces itself as, and an optional second line. Slint has no dialog role, so the card claims the closest landmark it has — a region — exactly as DialogPanel does, and this names it. |
description | in string | no default | |
dismiss-on-backdrop | in bool | true | When true, clicking outside the card dismisses the palette. |
panel-width | in length | 540px | Width of the card. |
Callbacks
| Callback | Description |
|---|---|
selected(string) | Fired with the chosen command's id. The palette closes itself. |
dismissed() | Fired when the palette closes itself — the backdrop or Escape. Running a command is not a dismissal: selected is the report for that. |
restore-focus() | Fired on EVERY close, including one the consumer drives by setting open = false, so keyboard focus always gets a new home: restore-focus => { my-button.focus(); }. Slint exposes no "previously focused element", so only the trigger's owner can name it. The same contract Dialog, Sheet and Drawer publish. |
Accessibility
- Landmark and role.
Commandexposes an accessible list structure containing individual list items with index information.CommandDialogclaims an accessibleregionlandmark named bylabeland described bydescription. - Keyboard focus trap.
CommandDialogbounds keyboard navigation within the dialog usingFocusSentinelmarkers, ensuring focus cannot wander outside the modal. - Focus restoration. Dismissing
CommandDialoginvokesrestore-focus, allowing applications to hand keyboard focus back to the originating button. - Group headings. Category headings are presented as non-focusable informative labels.
- Keyboard navigation. Navigation keys (↑/↓, Home/End) are captured by the ancestor focus scope before reaching the text input, giving navigation priority over caret positioning.