|
| 1 | +--- |
| 2 | +title: Adding Dock support to your extension |
| 3 | +description: Learn how to add Dock support to your Command Palette extension, allowing users to pin your commands to the persistent Dock toolbar. |
| 4 | +ms.date: 03/09/2026 |
| 5 | +ms.topic: how-to |
| 6 | +no-loc: [PowerToys, Windows, Insider] |
| 7 | +# Customer intent: As a Windows developer, I want to learn how to add Dock support to my Command Palette extension. |
| 8 | +--- |
| 9 | + |
| 10 | +# Adding Dock support to your extension |
| 11 | + |
| 12 | +**Previous**: [Get user input with forms](using-form-pages.md) |
| 13 | + |
| 14 | +The Command Palette [Dock](dock.md) is a persistent toolbar that stays visible at the edge of the user's screen. Extensions can provide **dock bands** — strips of items that appear in the Dock — to give users quick access to frequently used commands without opening the full Command Palette. |
| 15 | + |
| 16 | +> [!IMPORTANT] |
| 17 | +> Dock support requires **Command Palette Extension SDK version 0.9 or later**. Make sure your extension project references `Microsoft.CommandPalette.Extensions` version 0.9.260303001 or higher. |
| 18 | +
|
| 19 | +## Overview |
| 20 | + |
| 21 | +Dock support is provided through two interfaces: |
| 22 | + |
| 23 | +- **`ICommandProvider3`** — Adds the `GetDockBands()` method, which lets your extension provide dock bands. |
| 24 | +- **`ICommandProvider4`** — Adds the `GetCommandItem(string id)` method, which enables pinning of nested commands to the Dock. |
| 25 | + |
| 26 | +If you're using the `CommandProvider` base class from the toolkit, you can simply override these methods. |
| 27 | + |
| 28 | +## Add dock bands to your extension |
| 29 | + |
| 30 | +To provide dock bands, override the `GetDockBands()` method in your `CommandProvider` subclass. Each `ICommandItem` returned from this method is treated as one atomic band in the Dock. |
| 31 | + |
| 32 | +Here's a simple example that exposes a single command as a dock band: |
| 33 | + |
| 34 | +```csharp |
| 35 | +using Microsoft.CommandPalette.Extensions; |
| 36 | +using Microsoft.CommandPalette.Extensions.Toolkit; |
| 37 | + |
| 38 | +namespace <ExtensionName>; |
| 39 | + |
| 40 | +public partial class <ExtensionName>CommandsProvider : CommandProvider |
| 41 | +{ |
| 42 | + private readonly ICommandItem[] _commands; |
| 43 | + private readonly ICommandItem _dockBand; |
| 44 | + |
| 45 | + public <ExtensionName>CommandsProvider() |
| 46 | + { |
| 47 | + DisplayName = "My Extension"; |
| 48 | + Id = "com.mycompany.myextension"; |
| 49 | + |
| 50 | + var mainPage = new <ExtensionName>Page(); |
| 51 | + _dockBand = new CommandItem(mainPage) { Title = DisplayName }; |
| 52 | + _commands = [new CommandItem(mainPage) { Title = DisplayName }]; |
| 53 | + } |
| 54 | + |
| 55 | + public override ICommandItem[] TopLevelCommands() => _commands; |
| 56 | + |
| 57 | + public override ICommandItem[]? GetDockBands() |
| 58 | + { |
| 59 | + return [_dockBand]; |
| 60 | + } |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +When the user enables the Dock and adds your extension's band, it appears as a button in the Dock toolbar. |
| 65 | + |
| 66 | +## Create multi-button bands with WrappedDockItem |
| 67 | + |
| 68 | +If you want your dock band to display multiple buttons in a single strip, use the `WrappedDockItem` helper class. This lets you pass in an array of `IListItem` objects, and they're rendered as individual buttons within one band. |
| 69 | + |
| 70 | +```csharp |
| 71 | +using Microsoft.CommandPalette.Extensions; |
| 72 | +using Microsoft.CommandPalette.Extensions.Toolkit; |
| 73 | + |
| 74 | +namespace <ExtensionName>; |
| 75 | + |
| 76 | +public partial class <ExtensionName>CommandsProvider : CommandProvider |
| 77 | +{ |
| 78 | + public <ExtensionName>CommandsProvider() |
| 79 | + { |
| 80 | + DisplayName = "My Extension"; |
| 81 | + Id = "com.mycompany.myextension"; |
| 82 | + } |
| 83 | + |
| 84 | + public override ICommandItem[] TopLevelCommands() => []; |
| 85 | + |
| 86 | + public override ICommandItem[]? GetDockBands() |
| 87 | + { |
| 88 | + var button1 = new ListItem(new OpenUrlCommand("https://github.com")) |
| 89 | + { |
| 90 | + Title = "GitHub" |
| 91 | + }; |
| 92 | + var button2 = new ListItem(new OpenUrlCommand("https://learn.microsoft.com")) |
| 93 | + { |
| 94 | + Title = "Microsoft Learn" |
| 95 | + }; |
| 96 | + |
| 97 | + var band = new WrappedDockItem( |
| 98 | + [button1, button2], |
| 99 | + "com.mycompany.myextension.quicklinks", |
| 100 | + "Quick Links"); |
| 101 | + |
| 102 | + return [band]; |
| 103 | + } |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | +The `WrappedDockItem` class creates a band backed by a `ListPage` that holds your items. Each item in the array is rendered as a separate button in the Dock. |
| 108 | + |
| 109 | +> [!TIP] |
| 110 | +> You can also create a `WrappedDockItem` from a single `ICommand` by using the `WrappedDockItem(ICommand command, string displayTitle)` constructor. |
| 111 | +
|
| 112 | +## How dock bands work |
| 113 | + |
| 114 | +Each `ICommandItem` returned from `GetDockBands()` represents one atomic band. How the band is rendered depends on the `Command` property of the `ICommandItem`: |
| 115 | + |
| 116 | +| Command type | Dock behavior | |
| 117 | +| :--- | :--- | |
| 118 | +| `IInvokableCommand` | Renders as a single button that executes the command when selected. | |
| 119 | +| `IListPage` | Renders all items on the page as individual buttons in one band. | |
| 120 | +| `IContentPage` | Renders as a single expandable button with a flyout. | |
| 121 | + |
| 122 | +> [!NOTE] |
| 123 | +> All `ICommandItem` objects returned from `GetDockBands()` must have a `Command` with a non-empty `Id`. Items without an ID are ignored. |
| 124 | +
|
| 125 | +## Support pinning with GetCommandItem |
| 126 | + |
| 127 | +By default, users can only pin top-level commands and dock bands to the Dock. If you want users to be able to pin **nested commands** (commands that are deeper inside your extension), override the `GetCommandItem(string id)` method: |
| 128 | + |
| 129 | +```csharp |
| 130 | +public override ICommandItem? GetCommandItem(string id) |
| 131 | +{ |
| 132 | + var allCommands = GetAllAvailableItems(); |
| 133 | + foreach (var item in allCommands) |
| 134 | + { |
| 135 | + if (item?.Command is ICommand cmd && cmd.Id == id) |
| 136 | + { |
| 137 | + return item; |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + return null; |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +This method is called by the Command Palette when it needs to resolve a pinned command by its ID. If your extension doesn't override this method, only commands returned from `GetDockBands()` and `TopLevelCommands()` can be pinned. |
| 146 | + |
| 147 | +## Real-world example |
| 148 | + |
| 149 | +Here's how the built-in Time & Date extension provides a dock band that shows a live clock: |
| 150 | + |
| 151 | +```csharp |
| 152 | +public override ICommandItem[] GetDockBands() |
| 153 | +{ |
| 154 | + var bandItem = new NowDockBand(); |
| 155 | + var wrappedBand = new WrappedDockItem( |
| 156 | + [bandItem], |
| 157 | + "com.microsoft.cmdpal.timedate.dockBand", |
| 158 | + "Time & Date"); |
| 159 | + |
| 160 | + return [wrappedBand]; |
| 161 | +} |
| 162 | +``` |
| 163 | + |
| 164 | +The `NowDockBand` is a `ListItem` that updates its `Title` and `Subtitle` every minute to show the current time and date. This demonstrates how dock bands can display dynamic, live-updating content. |
| 165 | + |
| 166 | +## Related content |
| 167 | + |
| 168 | +- [Command Palette Dock](dock.md) |
| 169 | +- [Extensibility overview](extensibility-overview.md) |
| 170 | +- [Extension samples](samples.md) |
0 commit comments