Read-Only Mode and Preview Mode: Programmatic Control

    The WinForms HTML Editor exposes three operating modes through a single property on the control. Most "how do I make the editor read-only?" tickets boil down to picking the right mode and, where needed, hooking the click event so anchors still navigate.

    The three editor modes

    The mode is held in the EditorMode property of type SpiceLogic.HtmlEditor.Abstractions.EditorModes. The enum has three values:

    ValueWhat the user seesEditing
    WysiwygDesignRendered HTML with the caret and spell-check underline.Full WYSIWYG editing. Typing, paste, drag & drop, formatting commands all work.
    HtmlEditThe raw HTML source in a monospace textarea.The user edits markup directly. Formatting commands targeted at a rendered DOM are no-ops here.
    ReadOnlyPreviewRendered HTML exactly as a browser would show it, with no caret or selection chrome.None. Keystrokes are ignored. Hyperlinks become live (see below).

    Switching mode from C#

    Set the property at any time after the editor has loaded. The control fires EditorModeChanged after the swap is complete so you can update surrounding UI (status bar, custom ribbon, menu radio buttons) in one place.

    using SpiceLogic.HtmlEditor.Abstractions;
    
    // Switch to Preview (read-only render) on a button click:
    private void btnPreview_Click(object sender, EventArgs e)
    {
        htmlEditor1.EditorMode = EditorModes.ReadOnlyPreview;
    }
    
    // Be notified after the mode actually changes:
    htmlEditor1.EditorModeChanged += (s, e) =>
    {
        statusLabel.Text = $"Mode: {htmlEditor1.EditorMode}";
        toolbar1.Visible = htmlEditor1.EditorMode == EditorModes.WysiwygDesign;
    };
    Imports SpiceLogic.HtmlEditor.Abstractions
    
    End Sub
    ' Switch to Preview (read-only render) on a button click:
    Private Sub btnPreview_Click(sender As Object, e As EventArgs)
        htmlEditor1.EditorMode = EditorModes.ReadOnlyPreview
    
        ' Be notified after the mode actually changes:

    The event also fires when the user clicks the built-in Source / Preview toolbar buttons, so the same handler covers both code-driven and user-driven changes.

    Read-only without leaving Design view

    If you want the editing surface to stay rendered exactly as it is - for example after Save - but to stop accepting input, do not switch modes. Set htmlEditor1.Enabled = false. That disables the surface, the toolbar and the keyboard in one step, and re-enabling restores the caret where the user left it.

    htmlEditor1.Enabled = false; // lock
    htmlEditor1.Enabled = true; // unlock
    htmlEditor1.Enabled = False ' lock
    htmlEditor1.Enabled = True ' unlock

    Allowing link clicks in Preview

    In ReadOnlyPreview the editor renders anchors as live links. By default, a click opens the href in the system default browser (see "Opening a hyperlink in the default browser instead of MSIE" for the background on why this changed). To intercept the click and run your own logic - in-app navigation, analytics, a confirmation prompt - subscribe to HtmlElementClicked and check the element type:

    using SpiceLogic.HtmlEditor.Abstractions;
    using SpiceLogic.HtmlEditor.WinForms.Models.BOs.EditorEventArgs;
    
    htmlEditor1.HtmlElementClicked += (s, e) =>
    {
        if (htmlEditor1.EditorMode != EditorModes.ReadOnlyPreview)
            return;
        if (e.ElementType != HtmlElementTypes.Hyperlink)
            return;
        string href = e.ClickedElement.GetAttribute("href");
        MyAppRouter.Navigate(href); // your own handler
    };
    Imports SpiceLogic.HtmlEditor.Abstractions
    Imports SpiceLogic.HtmlEditor.WinForms.Models.BOs.EditorEventArgs
    
    htmlEditor1.HtmlElementClicked += Sub(s, e)
                                          If htmlEditor1.EditorMode IsNot EditorModes.ReadOnlyPreview Then Return
                                          If e.ElementType IsNot HtmlElementTypes.Hyperlink Then Return
                                          Dim href As String = e.ClickedElement.GetAttribute("href")
                                          MyAppRouter.Navigate(href) ' your own handler

    Your handler runs before the editor's built-in shell call. If you handle the URL yourself, the OS handoff effectively becomes a no-op because nothing in your code requested it.

    Hiding the toolbar in read-only mode

    The two factory toolbars are exposed as Toolbar1 and Toolbar2 (both ToolStrip instances). Toggle their Visible property from EditorModeChanged so the chrome follows the mode:

    htmlEditor1.EditorModeChanged += (s, e) =>
    {
        bool editing = htmlEditor1.EditorMode == EditorModes.WysiwygDesign;
        htmlEditor1.Toolbar1.Visible = editing;
        htmlEditor1.Toolbar2.Visible = editing;
        htmlEditor1.ToolbarFooter.Visible = editing;
    };
    htmlEditor1.EditorModeChanged += Sub(s, e)
                                         Dim editing As Boolean = htmlEditor1.EditorMode Is EditorModes.WysiwygDesign
                                         htmlEditor1.Toolbar1.Visible = editing
                                         htmlEditor1.Toolbar2.Visible = editing
                                         htmlEditor1.ToolbarFooter.Visible = editing

    Remembering the user's last mode across sessions

    Persist the enum value as its name (a string), not its integer - the int values are an implementation detail and could shift if new modes are ever added. Restore on load after the editor has finished initialising:

    // On form closing:
    Properties.Settings.Default.LastEditorMode = htmlEditor1.EditorMode.ToString();
    Properties.Settings.Default.Save();
    // On form load:
    if (Enum.TryParse<EditorModes>(Properties.Settings.Default.LastEditorMode, out var saved))
        htmlEditor1.EditorMode = saved;
    ' On form closing:
    Properties.Settings.[Default].LastEditorMode = htmlEditor1.EditorMode.ToString()
    Properties.Settings.[Default].Save()
    ' On form load:
    Dim saved = Nothing
    If [Enum].TryParse(Of EditorModes)(Properties.Settings.[Default].LastEditorMode, saved) Then htmlEditor1.EditorMode = saved

    Full example - preview-with-link-handling and Escape to go back

    using System;
    using System.Windows.Forms;
    using SpiceLogic.HtmlEditor.Abstractions;
    using SpiceLogic.HtmlEditor.WinForms;
    using SpiceLogic.HtmlEditor.WinForms.Models.BOs.EditorEventArgs;
    
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            htmlEditor1.EditorModeChanged += OnEditorModeChanged;
            htmlEditor1.HtmlElementClicked += OnHtmlElementClicked;
            htmlEditor1.KeyDown += OnEditorKeyDown;
        }
    
        private void btnPreview_Click(object sender, EventArgs e)
        {
            htmlEditor1.EditorMode = EditorModes.ReadOnlyPreview;
        }
    
        private void OnEditorModeChanged(object sender, EventArgs e)
        {
            bool editing = htmlEditor1.EditorMode == EditorModes.WysiwygDesign;
            htmlEditor1.Toolbar1.Visible = editing;
            htmlEditor1.Toolbar2.Visible = editing;
            statusLabel.Text = $"Mode: {htmlEditor1.EditorMode}";
        }
    
        private void OnHtmlElementClicked(object sender, HtmlElementClickedEventArgs e)
        {
            if (htmlEditor1.EditorMode != EditorModes.ReadOnlyPreview)
                return;
            if (e.ElementType != HtmlElementTypes.Hyperlink)
                return;
            string href = e.ClickedElement.GetAttribute("href");
            // Custom routing instead of letting the OS open the link:
            MyAppRouter.Navigate(href);
        }
    
        private void OnEditorKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape && htmlEditor1.EditorMode == EditorModes.ReadOnlyPreview)
            {
                htmlEditor1.EditorMode = EditorModes.WysiwygDesign;
                e.Handled = true;
            }
        }
    }
    Imports System
    Imports System.Windows.Forms
    Imports SpiceLogic.HtmlEditor.Abstractions
    Imports SpiceLogic.HtmlEditor.WinForms
    Imports SpiceLogic.HtmlEditor.WinForms.Models.BOs.EditorEventArgs
    
    End Sub
    
    Public Partial Class MainForm
        Inherits Form
        Public Sub New()
            InitializeComponent()
            htmlEditor1.EditorModeChanged += AddressOf OnEditorModeChanged
            htmlEditor1.HtmlElementClicked += AddressOf OnHtmlElementClicked
            htmlEditor1.KeyDown += AddressOf OnEditorKeyDown

    The same code path covers all three recurring tickets: the editor flips to a true read-only render, the toolbar disappears, links are still clickable (routed through your app), and Escape returns the user to Design without losing the document.

    Last updated on May 14, 2026