Table Authoring Service

    The Content.TableAuthoringService property on WinFormHtmlEditor exposes an ITableAuthoringService instance. The service owns every table-editing operation the user can perform from the table toolbar -- insert column, insert row, delete row, merge cells, and the zero-border guideline overlay. Calling these members from code is the supported way to drive table editing from a custom toolbar, a hotkey, or an automation script.

    Namespace: SpiceLogic.HtmlEditor.Abstractions.Services.ElementAuthoring
    Assembly: SpiceLogic.HtmlEditor.Abstractions.dll
    Accessor: htmlEditor1.Content.TableAuthoringService

    The service implements IDisposable; the editor owns its lifetime, so customer code never needs to call Dispose directly.

    InsertColumn(InsertPositions position)

    Inserts a new column adjacent to the table cell that currently contains the caret.

    Syntax
    void InsertColumn(InsertPositions position);
    Parameters
    NameTypeDescription
    positionInsertPositionsBefore inserts the new column to the left of the caret column; After inserts it to the right.
    Remarks

    Silently does nothing unless the editor is in EditorModes.WysiwygDesign mode and the caret is inside a table cell.

    Example
    using SpiceLogic.HtmlEditor.Abstractions;
    using SpiceLogic.HtmlEditor.Abstractions.Services.ElementAuthoring;
    
    ITableAuthoringService tables = htmlEditor1.Content.TableAuthoringService;
    // Insert a column to the right of the column under the caret.
    tables.InsertColumn(InsertPositions.After);
    Imports SpiceLogic.HtmlEditor.Abstractions
    Imports SpiceLogic.HtmlEditor.Abstractions.Services.ElementAuthoring
    
    Dim tables As ITableAuthoringService = htmlEditor1.Content.TableAuthoringService
    ' Insert a column to the right of the column under the caret.
    tables.InsertColumn(InsertPositions.After)

    DeleteColumn()

    Removes the column that contains the current cell from the table.

    Syntax
    void DeleteColumn();
    Remarks

    Silently does nothing unless the editor is in EditorModes.WysiwygDesign mode and the caret is inside a table cell. If the column is the only column in the table, the entire table is removed.

    Example
    if (MessageBox.Show("Delete this column?", "Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
    {
        htmlEditor1.Content.TableAuthoringService.DeleteColumn();
    }
    If MessageBox.Show("Delete this column?", "Confirm", MessageBoxButtons.YesNo) = DialogResult.Yes Then
        htmlEditor1.Content.TableAuthoringService.DeleteColumn()
    End If

    InsertRow(InsertPositions position)

    Inserts a new row adjacent to the row that contains the caret.

    Syntax
    void InsertRow(InsertPositions position);
    Parameters
    NameTypeDescription
    positionInsertPositionsBefore inserts the new row above the caret row; After inserts it below.
    Remarks

    Silently does nothing unless the editor is in EditorModes.WysiwygDesign mode and the caret is inside a table cell.

    Example
    // Hot-key handler for Ctrl+Enter -- append a new row below.
    private void AppendRow_Click(object sender, EventArgs e)
    {
        htmlEditor1.Content.TableAuthoringService.InsertRow(InsertPositions.After);
    }
    ' Hot-key handler for Ctrl+Enter -- append a new row below.
    Private Sub AppendRow_Click(sender As Object, e As EventArgs)
        htmlEditor1.Content.TableAuthoringService.InsertRow(InsertPositions.After)
    End Sub

    DeleteRow()

    Removes the row that contains the caret from the table.

    Syntax
    void DeleteRow();
    Remarks

    Silently does nothing unless the editor is in EditorModes.WysiwygDesign mode and the caret is inside a table cell. If the row is the only row in the table, the entire table is removed.

    Example
    htmlEditor1.Content.TableAuthoringService.DeleteRow();

    MergeSelectedCells()

    Merges the currently selected table cells into one. Styling on the resulting cell is inherited from the top-left source cell.

    Syntax
    void MergeSelectedCells();
    Remarks

    The call is a no-op when CanMergeCells() returns false or when EnableTableCellMerging is false. Guard custom toolbar buttons with CanMergeCells() so their enabled state matches. Unlike the row and column operations above, this runs regardless of editor mode.

    Example
    var tables = htmlEditor1.Content.TableAuthoringService;
    if (tables.CanMergeCells())
    {
        tables.MergeSelectedCells();
    }
    Dim tables = htmlEditor1.Content.TableAuthoringService
    
    If tables.CanMergeCells() Then
        tables.MergeSelectedCells()
    End If

    ShowGuidelinesForTablesWithZeroBorder(bool inBackground = false)

    Renders a dashed guideline overlay around every table whose border attribute is 0. The guideline is purely a visual aid -- it is not serialized into the document HTML.

    Syntax
    void ShowGuidelinesForTablesWithZeroBorder(bool inBackground = false);
    Parameters
    NameTypeDescription
    inBackgroundboolWhen true, the whole-document scan runs on a background thread instead of blocking the caller; a background call issued while a previous background pass is still running for the same operation is dropped rather than queued, and any exception is swallowed. Defaults to false, which runs synchronously on the caller's thread and lets any exception propagate.
    Remarks

    Silently does nothing unless the editor is in EditorModes.WysiwygDesign mode. The guideline CSS is customizable via Options.ZeroBorderTableGuidelineCss.

    Example
    // Toggle the guideline overlay from a toolbar button.
    htmlEditor1.Content.TableAuthoringService
        .ShowGuidelinesForTablesWithZeroBorder();

    HideGuidelinesOfTablesWithZeroBorder(bool inBackground = false)

    Removes the dashed guideline overlay added by ShowGuidelinesForTablesWithZeroBorder.

    Syntax
    void HideGuidelinesOfTablesWithZeroBorder(bool inBackground = false);
    Parameters
    NameTypeDescription
    inBackgroundboolWhen true, the whole-document revert scan runs on a background thread instead of blocking the caller, with the same drop-if-already-running behavior as ShowGuidelinesForTablesWithZeroBorder. Defaults to false, which runs synchronously on the caller's thread and lets any exception propagate.
    Remarks

    Silently does nothing unless the editor is in EditorModes.WysiwygDesign mode.

    Example
    htmlEditor1.Content.TableAuthoringService
        .HideGuidelinesOfTablesWithZeroBorder();

    IsTableBorderZero(IHTMLElement tableElement)

    Tests whether a given <table> element has an effective border of zero -- via the border="0" attribute or via CSS that resolves to no visible border.

    Syntax
    bool IsTableBorderZero(IHTMLElement tableElement);
    Parameters
    NameTypeDescription
    tableElementmshtml.IHTMLElementThe MSHTML <table> element to test.
    Returns

    true when the table has no visible border; otherwise false.

    Example
    using mshtml;
    
    var tables = htmlEditor1.Content.TableAuthoringService;
    IHTMLElement selected = htmlEditor1.StateQuery.GetActiveHtmlElement();
    if (selected?.tagName == "TABLE" && tables.IsTableBorderZero(selected))
    {
        tables.ShowGuidelinesForTablesWithZeroBorder();
    }
    Imports mshtml
    
    Dim tables = htmlEditor1.Content.TableAuthoringService
    Dim selected As IHTMLElement = htmlEditor1.StateQuery.GetActiveHtmlElement()
    
    If selected?.tagName = "TABLE" AndAlso tables.IsTableBorderZero(selected) Then
        tables.ShowGuidelinesForTablesWithZeroBorder()
    End If

    CanMergeCells()

    Reports whether the current selection covers two or more adjacent cells eligible for merging.

    Syntax
    bool CanMergeCells();
    Returns

    true when cells can be merged; otherwise false.

    Remarks

    Bind this to the Enabled of a custom Merge-Cells toolbar button inside SelectionChanged so the button greys out automatically when merging is not possible.

    Example
    htmlEditor1.SelectionChanged += (s, e) =>
    {
        mergeButton.Enabled = htmlEditor1.Content.TableAuthoringService.CanMergeCells();
    };

    GetTableManipulator()

    Returns the ITableManipulator state-query helper, created once per document the first time it is requested and cached from then on -- it is not re-created per call or scoped to the caret. Its public surface is a single state-query member, CanMerge(), which CanMergeCells forwards to.

    Syntax
    ITableManipulator GetTableManipulator();
    Returns

    The current ITableManipulator instance. It is never null, regardless of caret position; call ResetTableManipulator to force a fresh instance.

    Example
    var manipulator = htmlEditor1.Content.TableAuthoringService.GetTableManipulator();
    Debug.WriteLine($"Selection can be merged: {manipulator.CanMerge()}");
    Dim manipulator = htmlEditor1.Content.TableAuthoringService.GetTableManipulator()
    
    Debug.WriteLine($"Selection can be merged: {manipulator.CanMerge()}")

    ResetTableManipulator()

    Immediately disposes the cached ITableManipulator and creates a fresh one, rather than deferring the re-creation to the next GetTableManipulator call. Call this after a programmatic edit you suspect invalidated the cached state -- for example, after replacing the document HTML wholesale.

    Syntax
    void ResetTableManipulator();
    Remarks

    This also re-derives EnableTableCellMerging from Options.EnableTableCellMerge, discarding any value set directly on the property beforehand.

    Example
    htmlEditor1.Content.SetBodyHtml("<table border=\"1\"><tr><td>A</td></tr></table>");
    htmlEditor1.Content.TableAuthoringService.ResetTableManipulator();

    SelectedCellBackgroundColor Property

    Gets or sets the background color used to highlight selected table cells on the editor surface. This is a UI-only highlight; it does not emit a background-color style on the cells themselves.

    Syntax
    Color SelectedCellBackgroundColor { get; set; }
    Property Value

    A System.Drawing.Color. The default is a light-blue overlay; pick any color that contrasts with your document background.

    Example
    using System.Drawing;
    
    htmlEditor1.Content.TableAuthoringService.SelectedCellBackgroundColor = Color.FromArgb(120, 255, 230, 0); // semi-transparent yellow
    
    Imports System.Drawing
    
    htmlEditor1.Content.TableAuthoringService.SelectedCellBackgroundColor = Color.FromArgb(120, 255, 230, 0) ' semi-transparent yellow

    EnableTableCellMerging Property

    Gets or sets whether the cell-merging feature is enabled. When false, MergeSelectedCells is a no-op and the editor suppresses any cell-selection UI.

    Syntax
    bool EnableTableCellMerging { get; set; }
    Property Value

    true to allow cell merging; false to disable it. This is initialized from Options.EnableTableCellMerge at startup, and again every time ResetTableManipulator runs.

    Example
    // Disable cell merging for a simplified authoring mode.
    htmlEditor1.Content.TableAuthoringService.EnableTableCellMerging = false;
    ' Disable cell merging for a simplified authoring mode.
    htmlEditor1.Content.TableAuthoringService.EnableTableCellMerging = False

    Ask your AI to do this

    Let your assistant do this for you. With the SpiceLogic MCP server connected, paste this into Claude Code, Cursor, or VS Code Copilot in agent mode.

    Using the SpiceLogic WinForms HTML Editor already referenced in my project, build a small custom toolbar with an "Add column" button that calls InsertColumn on the editor's Content.TableAuthoringService (typed as ITableAuthoringService) to insert a column next to whatever table cell currently holds the caret. Add a second button that removes the current row through the same service, so both actions work from my own toolbar instead of the built-in table commands. Pull the exact ITableAuthoringService method signatures with the SpiceLogic MCP tools before writing any code.

    Last updated on May 14, 2026

    Put this into practice.

    .NET WinForms HTML Editor Control ships with free C# and VB.NET sample projects and a 14-day evaluation.

    Prefer a guided look? Book a free live demo with our engineers - live on Zoom or Teams, never a chatbot.