Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
To display plain text on a web page, escape characters that HTML treats as markup, then place the result inside an appropriate HTML element. Escaping keeps input such as <tag> literal; it does not turn plain text into paragraphs, headings, or links. If your source is Markdown and you want its syntax converted into HTML, use a Markdown parser instead—and handle untrusted input separately for security.
First decide what “convert” means
Plain text and HTML solve different problems. Plain text is content without HTML markup. HTML describes a document’s structure and can also contain text that should display literally. A conversion task can therefore mean one of two things:
- Display text as entered: encode HTML-significant characters so the browser shows them as text instead of interpreting them as markup.
- Build a formatted document: decide which parts should be paragraphs, headings, lists, links, or other elements, then create that HTML structure.
These steps are not interchangeable. Escaping protects the literal characters; it does not infer the document outline or automatically make a line of text into a heading. If the input uses Markdown conventions such as # Heading or * item, use a Markdown parser to translate those conventions rather than treating the source as ordinary prose.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchDisplay plain text safely in HTML
For text in an HTML text node, encode characters that could otherwise be parsed as markup. At minimum, the ampersand and angle brackets need to be represented safely. In Python, the standard-library html.escape() function does this; its default quote=True also encodes single and double quotation marks.
#1 Best Overall
import html
plain_text = 'Use <tag> & "quotes"'
safe_text = html.escape(plain_text)
html_fragment = f'<p>{safe_text}</p>'
print(html_fragment)
The resulting fragment displays the original characters inside a paragraph rather than treating <tag> as an element. This example is specifically for an HTML text node. If you put a value into an attribute, URL, JavaScript, CSS, or another parsing context, use a method designed for that context instead of assuming HTML text escaping is universal.
Use browser text insertion when you have a DOM element
In browser-side JavaScript, assign plain text with textContent when the intention is to show it literally:
const output = document.querySelector('#output');
const plainText = 'Use <tag> & "quotes"';
output.textContent = plainText;
Given a page containing <div id="output"></div>, the text is inserted as text rather than parsed as HTML. OWASP recommends textContent as a safe sink for plain-text insertion. That does not secure other destinations: an attribute, event handler, URL, or JavaScript context has different rules.
Free tools Windows power users keep installed
One-click scans. No signup required.
Create structure deliberately
Once text is safe to display, decide how it should read on the page. For example, if a source has a title and two paragraphs, encode each text value and put it into the element that matches its role:
Rank #2
import html
source_title = 'Release & Support'
source_paragraphs = [
'The update is ready.',
'See <status> for service details.'
]
title = html.escape(source_title)
paragraphs = ''.join(
f'<p>{html.escape(paragraph)}</p>'
for paragraph in source_paragraphs
)
html_document = f'<h1>{title}</h1>{paragraphs}'
This code assumes the input has already been divided into a title and paragraph strings. That separation is a content decision, not something html.escape() discovers. For a longer document, choose a consistent rule for headings, paragraphs, and lists before generating markup.
Preserve line breaks only when the output design calls for them
Escaping does not preserve visual line breaks as HTML line breaks. Choose how each newline should behave: it could separate paragraphs, separate list items, or simply be treated as whitespace. For paragraph-style text, split the source into paragraphs and wrap each one in a <p> element. If each newline should create a visible break within the same block, insert <br> elements between escaped lines. Do not insert raw input into the HTML while doing this; escape each text segment, and add only the markup your application intends to generate.
Convert Markdown when the source is Markdown
Markdown is plain text with conventions intended to represent structure. If you want those conventions translated into HTML, use a Markdown parser rather than escaping the whole input. Python-Markdown provides a convert(source) method:
import markdown
source = """# Update
The release is ready.
- Read the notes
- Check the status page
"""
html_output = markdown.Markdown().convert(source)
print(html_output)
This converts Markdown syntax into HTML elements. It is not the same operation as safely displaying literal text: for example, a Markdown heading marker is intended to become a heading, while a literal less-than sign in ordinary prose should remain text.
Rank #3
Markdown conversion is not sanitization
Python-Markdown explicitly warns that it does not sanitize the HTML it generates. If the Markdown comes from an untrusted user, do not assume parsing makes the result safe to render. Apply an appropriate sanitization step for the application and trust boundary before presenting generated HTML. Output encoding and sanitization address different concerns; select the right handling for the eventual destination.
Handle untrusted input at the output boundary
Do not concatenate unescaped user-controlled text into an HTML string and send it to a browser. Characters such as < and & have meaning in HTML parsing, so untrusted values need context-appropriate handling if they are meant to appear as data. The OWASP Foundation’s Cross Site Scripting Prevention Cheat Sheet explains: “The purpose of output encoding (as it relates to XSS) is to convert untrusted input into a safe form where the input is displayed as data to the user without executing as code in the browser.”
- HTML text: encode for a text node, or use a plain-text DOM API such as
textContent. - Attributes and other contexts: use the encoding or API intended for that destination; text-node encoding is not a universal substitute.
- Markdown-generated HTML: treat conversion and sanitization as separate steps when the source is untrusted.
Prefer keeping the original source as the canonical data and applying the appropriate encoding near the point where it is rendered. Permanently storing HTML-escaped text can cause problems if the same value later needs to be used in a different context. Also avoid escaping the same content twice: repeated encoding can make users see entity spellings such as & instead of an ampersand.
Recommended Free Tools
Or skip the browser setup
If you have generated an HTML page and want a screenshot of how it renders, ScreenshotNeo can capture a URL as an image or PDF. It is a screenshot API, not a plain-text-to-HTML converter: you still need to generate and serve the HTML page. For example, if your rendered page is available at https://example.com, this cURL request saves a WebP screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo documentation for API parameters. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Sign up for ScreenshotNeo’s free plan.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot common conversion problems
The page shows literal tags or entity spellings
If a tag appears as text, that is expected when markup has been escaped: the browser is displaying it literally. If an ampersand appears as &, the value may have been escaped more than once. Keep the original value and apply one appropriate encoding step at the rendering boundary.
Text breaks or paragraphs do not appear
Escaping does not create paragraph elements or visible line breaks. Check the source’s newline conventions, then explicitly split it into the paragraph or line units your layout requires and add the corresponding elements.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Markdown markers remain visible
Escaping or displaying text literally will not translate Markdown. If the input is intended to be Markdown, run it through a Markdown parser. If it is ordinary prose, visible marker characters may be the correct result.
User input changes the page structure
This can happen when untrusted content is inserted as HTML instead of text, or when conversion output is rendered without appropriate safety handling. Use a plain-text insertion path for literal text; for generated HTML from untrusted Markdown, add a suitable sanitization step. Review the actual destination context rather than relying on one escaping method for every use.
Best Value
Text is safe in one place but unsafe in another
Encoding is context-specific. A value handled for an HTML text node should not automatically be reused in an attribute, URL, JavaScript, or CSS position. Use a mechanism designed for the target context, and avoid assembling executable code or markup from untrusted pieces.
Choose the right conversion path
| Input and goal | Approach | Key consideration |
|---|---|---|
| Ordinary prose that should display literally | Encode for an HTML text node or insert with textContent |
Choose paragraphs and other structure separately. |
| Text that needs a deliberate document layout | Build the desired HTML elements and place safely handled text inside them | Escaping does not infer headings, lists, or paragraph boundaries. |
| Markdown whose conventions should become elements | Use a Markdown parser | Parsing does not by itself sanitize output from untrusted input. |
The deciding questions are what format the source uses, whether its characters should remain literal or become structure, whether the content is trusted, and where the result will be inserted. Answer those first, then choose encoding, parsing, and sanitization steps that fit.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Frequently Asked Questions
Can I convert a .txt file directly into an HTML file?
Yes. Read its text, decide how newlines and sections should map to HTML, encode literal text for its destination, and write the generated markup to an .html file.
Do I need to escape quotes in ordinary HTML text?
Python’s html.escape() escapes quotes by default, but the required handling depends on the destination. For an HTML text node, the main concern is preventing markup-significant characters from being interpreted; attributes and other contexts require context-appropriate handling.
Is HTML escaping enough to prevent every XSS issue?
No. Escaping is specific to an output context and is not a universal sanitizer. Use the handling appropriate to the destination, and sanitize generated HTML where the trust boundary requires it.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

