Format Painter in ASP.NET Core: Building Custom Text Formatting with TX Text Control
This article demonstrates how to build a Format Painter feature using the TX Text Control Document Editor, implementing format detection, copy and paste operations, and custom style handling through the JavaScript API.

Anyone who has spent time in Microsoft Word knows the magic of the Format Painter: a feature that lets you copy formatting from one piece of text and apply it to another with a single click. Although Format Painter functionality exists in common web editors, developers creating custom document applications require more sophisticated formatting controls. The TX Text Control rich text editor enables developers to implement custom formatting programmatically. This article demonstrates how to build a Format Painter feature using the TX Text Control Document Editor, implementing format detection, copy and paste operations, and custom style handling through the JavaScript API.
Understanding Uniform Formatting Detection
Building a reliable Format Painter feature starts with solving one key challenge: how do you know if the selected text has consistent formatting? When users select text with mixed fonts, colors, or styles, copying that formatting creates inconsistent results. TX Text Control's is
Getting Started
Learn how to create the TX Text Control rich text editor with ASP.NET Core using this guide:
The ASP.NET Core application with TX Text Control provides rich text editing with comprehensive functionality. The JavaScript API enables further customization and integration with specialized features, such as the Format Painter. For demonstration purposes, this implementation utilizes dedicated buttons to showcase the Format Painter functionality. The complete source code for this implementation is available on the TX Text Control GitHub repository. The project includes all the code examples, along with the complete ASP.NET Core setup and JavaScript integration.
Implementing Asynchronous Format Detection
Since TX Text Control uses callback-based APIs for asynchronous operations, the implementation converts these to Promise wrappers for cleaner async/await syntax. The isCommonValueSelectedAsync function specifically handles format validation using the is
// Global variables
let copiedFormat = null;
let styleCounter = 1;
let customStyles = {};
// Promise wrappers for TX Text Control API
const get = (method) =>
new Promise((resolve, reject) =>
TXTextControl.selection[method](v => resolve(v), e => reject(e))
);
const set = (method, val) =>
new Promise((resolve, reject) =>
TXTextControl.selection[method](val, () => resolve(), e => reject(e))
);
const getLength = () =>
new Promise((resolve, reject) =>
TXTextControl.selection.getLength(v => resolve(v), e => reject(e))
);
const selectWord = () =>
new Promise((resolve, reject) =>
TXTextControl.selectWord(() => resolve(), e => reject(e))
);
// Utility function to check if selected text has uniform formatting
function isCommonValueSelectedAsync(selection, attr) {
return new Promise((resolve, reject) => {
selection.isCommonSelectionValueSelected(
attr,
(result) => {
resolve(result); // true/false
},
reject
);
});
}
Copying Formatting From Text Selection
The event handler shown below validates the text selection and captures its formatting attributes only if the text selection has uniform formatting:
// Main event handler - runs when TX Text Control is fully loaded
TXTextControl.addEventListener("textControlLoaded", () => {
// Get references to all UI elements
const copyFormatButton = document.getElementById("copyFormatButton");
const pasteFormatButton = document.getElementById("pasteFormatButton");
const createStyleButton = document.getElementById("createStyleButton");
const customStylesDropdown = document.getElementById("customStylesDropdown");
const applyStyleButton = document.getElementById("applyStyleButton");
// Copy formatting from selected text
copyFormatButton.addEventListener("click", async () => {
// Validate that selection has uniform formatting
const isUniform = await isCommonValueSelectedAsync(
TXTextControl.selection,
TXTextControl.Selection.Attribute.All
);
if (isUniform) {
// Capture all formatting attributes from current selection
copiedFormat = {
baseline: await get("getBaseline"),
bold: await get("getBold"),
fontName: await get("getFontName"),
fontSize: await get("getFontSize"),
foreColor: await get("getForeColor"),
italic: await get("getItalic"),
strikeout: await get("getStrikeout"),
textBackColor: await get("getTextBackColor"),
underline: await get("getUnderline")
};
pasteFormatButton.disabled = false;
console.log("Format copied successfully.");
} else {
alert("Please select text with uniform formatting to copy the format.");
}
});
Applying Formatting to Text Selections
The paste handler applies the previously copied formatting to the target selection with all the captured attributes, as shown in this code:
// Apply previously copied formatting to current selection
pasteFormatButton.addEventListener("click", async () => {
if (!copiedFormat) {
pasteFormatButton.disabled = true;
return;
}
try {
// Apply all captured formatting attributes to current selection
await set("setBaseline", copiedFormat.baseline);
await set("setBold", copiedFormat.bold);
await set("setFontName", copiedFormat.fontName);
await set("setFontSize", copiedFormat.fontSize);
await set("setForeColor", copiedFormat.foreColor);
await set("setItalic", copiedFormat.italic);
await set("setStrikeout", copiedFormat.strikeout);
await set("setTextBackColor", copiedFormat.textBackColor);
await set("setUnderline", copiedFormat.underline);
console.log("Format pasted successfully.");
} catch (err) {
alert("Paste failed: " + err.message);
console.error(err);
}
});
Creating Custom Styles and Adding Them to TX Text Control's Style Collection
This section shows how to create reusable styles that become part of TX Text Control's style collection. Unlike the copy and paste formatting covered earlier, creating custom styles defines inline or paragraph formatting rules that can be reapplied across the document or in future editing sessions. The created custom styles are added to the Document Editor's "Styles" dropdown in the ribbon.
TX Text Control supports both inline and paragraph styles, which serve different formatting purposes:
- Paragraph styles apply formatting to entire paragraphs.
- Inline styles apply character-level formatting to selected text portions within paragraphs.
This implementation uses inline styles because the format painter feature captures character-level formatting properties. Formatting is applied to selected text portions rather than entire paragraphs. The following code shows how to create styles and add them to TX Text Control's style collection:
// Create a reusable style from selected text formatting
createStyleButton.addEventListener("click", async () => {
try {
// Validate uniform formatting before creating style
const isUniform = await isCommonValueSelectedAsync(
TXTextControl.selection,
TXTextControl.Selection.Attribute.All
);
if (!isUniform) {
alert("Please select text with uniform formatting to create a style.");
return;
}
// Capture current selection's formatting
const currentFormat = {
baseline: await get("getBaseline"),
bold: await get("getBold"),
fontName: await get("getFontName"),
fontSize: await get("getFontSize"),
foreColor: await get("getForeColor"),
italic: await get("getItalic"),
strikeout: await get("getStrikeout"),
textBackColor: await get("getTextBackColor"),
underline: await get("getUnderline")
};
// Generate unique style name and create the style
const styleName = "CustomStyle" + styleCounter++;
// Add the created style in TX Text Control's inline styles collection
const addedStyle = await addStyle(styleName, currentFormat, "inline");
if (addedStyle) {
// Store for dropdown usage and add to UI
customStyles[styleName] = { ...currentFormat };
addStyleToDropdown(styleName);
}
alert(`Custom style '${styleName}' created successfully!`);
} catch (err) {
alert("Style creation failed: " + err.message);
console.error(err);
}
});
Note: TX Text Control's FormattingStyle.setFontSize Method requires font sizes in twips (1/20th of a point). The ptToTwips helper function converts point values to twips, ensuring programmatically created styles display at the correct font size.
// Convert font size from points to twips (required by TX Text Control)
function ptToTwips(pt) {
return pt * 20;
}
// Function to create a new inline style in TX Text Control's style collection
function addStyle(styleName, format) {
return new Promise((resolve, reject) => {
TXTextControl.inlineStyles.add(
styleName,
(style) => {
// Apply formatting values to the new style
style.setFontName(format.fontName);
style.setFontSize(ptToTwips(format.fontSize)); // Convert to twips
style.setForeColor(format.foreColor);
style.setBold(format.bold);
style.setItalic(format.italic);
style.setUnderline(format.underline);
style.setStrikeout(format.strikeout);
style.setBaseline(format.baseline);
style.setTextBackColor(format.textBackColor);
resolve(style);
},
(error) => reject(error)
);
});
}
Conclusion
This article demonstrates how to build a professional Format Painter feature for ASP.NET applications using TX Text Control's JavaScript API. The implementation uses the isCommonSelectionValueSelected Method to ensure uniform formatting detection. It also includes complete functionality for copying and pasting formats, creating custom styles, and adding them to the TX Text Control style collection using inline styles. This approach provides developers with a practical foundation for implementing sophisticated text formatting in web-based applications.
Also See
This post references the following in the documentation:
- Javascript: Selection.is
Common Selection Value Selected Method - Javascript: Inline
Style Collection Object - Javascript: Paragraph
Style Collection Object
Download and Fork This Sample on GitHub
We proudly host our sample code on github.com/TextControl.
Please fork and contribute.
Requirements for this sample
- TX Text Control .NET Server 33.0
- Visual Studio 2022
Related Posts
Observe When the Reporting Preview Tab is Active Using MutationObserver
This article shows how to observe when the Reporting Preview tab is active using MutationObserver. The Reporting Preview tab is a feature of the TX Text Control Document Editor that allows you to…
Building an ASP.NET Core Backend Application to Host the Document Editor and…
This article explains how to create an ASP.NET Core backend application to host the Document Editor and Document Viewer. This backend application is required to provide the required functionality…
JavaScriptASP.NET CoreDocument Editor
Getting Started: Document Editor with JavaScript
This article shows how to use the TX Text Control document editor in a pure HTML and JavaScript environment.
ASP.NETASP.NET CoreDocument Editor
Getting Started Video Tutorial: Document Editor in ASP.NET Core C# on Linux
This video tutorial shows how to use the Document Editor in an ASP.NET Core application using C# and deploy on Linux using Docker. This tutorial is part of the TX Text Control Getting Started…
Add JavaScript to PDFs with TX Text Control in C# .NET: Time-Based Alerts…
In this article, we explore how to enrich PDF documents with JavaScript using TX Text Control in C# .NET. Read on to learn how to create time-based alerts that trigger actions based on specific…