Override toolbar button properties and click behavior
Jacob builds the runbook authoring tool at a managed-services provider. Engineers use his app to draft, version, and ship the troubleshooting runbooks their NOC team follows at three in the morning. Runbooks are HTML documents with screenshots, command snippets, and tables of escalation contacts. The editor is WinFormHtmlEditor.
The annoyance that's been on Jacob's desk for a quarter is the Save button. When an engineer clicks the toolbar's Save icon, the editor pops a standard SaveFileDialog - the OS file picker. That made sense in 2014. In 2026 Jacob's runbooks are not files on disk; they are versioned documents in his app's SQL backend, with audit trails, peer-review requirements, and a custom commit-message dialog. He needs the editor's Save button to call his pipeline, not show a file picker.
While he is at it, he also wants the disk icon on the Save button to match the rest of his app's visual language, and he wants the tooltip to say "Commit runbook (Ctrl+S)" instead of the generic "Save".
Layer 1: Jacob fixes the icon and tooltip at design time
Every built-in toolbar item is exposed as a typed ToolStripButton property on WinFormHtmlEditor. Jacob selects the editor on his runbook form, walks the Document Outline, and finds BtnSave. It is a real ToolStripButton, so the Properties window shows Image, Text, ToolTipText, Visible, Enabled, DisplayStyle, Alignment - the full set. He drops in his own 16x16 commit icon and changes the tooltip text to "Commit runbook (Ctrl+S)". The designer persists both.

Layer 2: runtime tweaks for state-dependent UI
Some of Jacob's state has to live in code. The Save button should be disabled when the runbook hasn't changed, hidden entirely when the engineer is in read-only review mode, and re-enabled after every keystroke. He reaches the same button from code:
private void RunbookForm_Load(object sender, EventArgs e)
{
htmlEditor1.BtnSave.Visible = !isReviewMode;
htmlEditor1.BtnSave.Enabled = false;
htmlEditor1.HtmlChanged += (s, a) => htmlEditor1.BtnSave.Enabled = true;
// Hide Paste-From-Word for engineers without an Office license.
htmlEditor1.BtnPasteFromMsWord.Visible = userHasOfficeLicense;
}Every built-in button is reachable the same way. The full set Jacob has on tap: BtnNew, BtnOpen, BtnSave, BtnCut, BtnCopy, BtnPaste, BtnPasteFromMsWord, BtnBold, BtnItalic, BtnUnderline, BtnFormatReset, BtnFormatUndo, BtnFormatRedo, BtnPrint, BtnSpellCheck, BtnSearch, BtnHighlightColor, BtnFontColor, BtnHyperlink, BtnImage, BtnInsertYouTubeVideo, BtnTable, BtnSymbol, BtnHorizontalRule, BtnOrderedList, BtnUnOrderedList, BtnAlignLeft, BtnAlignCenter, BtnAlignRight, BtnOutdent, BtnIndent, BtnStrikeThrough, BtnSuperScript, BtnSubscript, BtnBodyStyle. Combos: CmbFontName, CmbFontSize, CmbTitleInsert.
Layer 3: actually replacing the click behavior
The icon and tooltip changes only made the button look different. The click still opens the OS file picker - that is what Jacob really needs to replace. He subscribes to ToolbarItemOverrider.SaveButtonClicked. The rule, baked into every override handler in the helper class, is that when a customer handler is attached, the editor's default action does not run - your code does instead.
private void RunbookForm_Load(object sender, EventArgs e)
{
htmlEditor1.ToolbarItemOverrider.SaveButtonClicked += (s, e) =>
{
// Skip the OS file picker entirely. Run the company commit pipeline.
var commitMessage = CommitMessageDialog.ShowDialog(htmlEditor1);
if (commitMessage == null) return;
var html = htmlEditor1.Content.GetDocumentHtml();
RunbookRepository.Commit(currentRunbookId, html, commitMessage, currentUser);
htmlEditor1.BtnSave.Enabled = false; // re-enabled on next HtmlChanged
};
}
The toolbar button still looks like a Save button (Jacob's icon, Jacob's tooltip). The keyboard shortcut still fires the same handler. But the action is his commit pipeline - audit trail, peer-review queue, SQL backend.
The full override menu
Jacob ends up overriding three buttons total: Save (commit pipeline), New (clear-with-confirmation), and Print (render-to-PDF service). The same pattern works for everything else. Events open for override on ToolbarItemOverrider include BoldButtonClicked, ItalicButtonClicked, UnderlineButtonClicked, ImageButtonClicked, HyperLinkButtonClicked, TableInsertButtonClicked, NewButtonClicked, OpenButtonClicked, SaveButtonClicked, PrintButtonClicked, SpellCheckButtonClicked, SearchButtonClicked, SymbolInsertButtonClicked, YouTubeVideoInsertButtonClicked, plus the combo-value-changed events FontNameComboValueChanged, FontSizeComboValueChanged, and TitleInsertComboValueChanged. The complete set lives in ToolbarItemOverrideHelper.
Picking the right layer
- Just change icon, tooltip, or visibility? Edit the
BtnXxxproperty in the designer or at runtime. - Add work alongside the editor's action - audit log, telemetry, validation? Subscribe to
ToolbarItemOverrider.XxxButtonClickedand call the matchingFormatting/Content/Editorservice yourself afterward. - Replace the action entirely with your own dialog or pipeline? Subscribe and do not call the original service.