Text to HTML Converter

Paragraphs, line breaks and lists from plain text, with every character escaped before any tag is added, so AT&T and <script> come out as words.

Enable JavaScript to customise; default output below.

Blank lines separate paragraphs. Lines starting with a dash or a number become list items.

Leave empty for no rel. "noopener" is the sensible default; add "nofollow" for user-submitted text.

Indent list items with
Live preview text.html
<p>Release notes for 2.4</p>
<p>It ships faster sync &amp; a fix for &lt;script&gt;alert(1)&lt;/script&gt; in titles.<br />
Read more at <a href="https://swiftplugins.pro/changelog" rel="noopener">https://swiftplugins.pro/changelog</a> or mail <a href="mailto:[email protected]">[email protected]</a>.</p>
<ul>
	<li>Faster sync</li>
	<li>Fixed the import bug</li>
	<li>AT&amp;T edge case</li>
</ul>
<ol>
	<li>Back up</li>
	<li>Update</li>
	<li>Clear the cache</li>
</ol>

<!--
Text in      268 characters
HTML out     480 characters
Paragraphs   2
List items   6
Line breaks  kept as <br />

Escaping happens before any tag is added, so text containing angle
brackets or an ampersand comes out as characters rather than as markup.
The ampersand is escaped first, or the escapes of the other characters
get escaped again and you see &amp;lt; in the output.

Links are built from the already-escaped text and only from http and
https addresses, so nothing in the input can close the attribute or
smuggle a javascript: URL into an href.
-->

Output is valid and updates as you type.

Plain text into HTML: blank lines become paragraphs, single newlines become line breaks, and lines starting with a dash or a number become list items.

The part that matters is the order. Every character is escaped before any tag is added, so text containing <script> comes out as visible characters and AT&T survives. Converters that add the paragraphs first escape their own tags; ones that escape only the angle brackets leave the ampersand to be reinterpreted, and AT&T becomes something else on the next round trip.

How to use

  1. Paste the text.
  2. Decide whether single newlines should become <br /> — off is usually right for prose, on for addresses and poetry.
  3. Turn autolinking on if the output is going somewhere that will not linkify by itself.

Example

<p>Release notes for 2.4</p>
<p>It ships faster sync &amp; a fix for &lt;script&gt;alert(1)&lt;/script&gt; in titles.<br />
Read more at <a href="https://swiftplugins.pro/changelog" rel="noopener">https://swiftplugins.pro/changelog</a> or mail <a href="mailto:[email protected]">[email protected]</a>.</p>
<ul>
	<li>Faster sync</li>
	<li>Fixed the import bug</li>
	<li>AT&amp;T edge case</li>
</ul>
<ol>
	<li>Back up</li>
	<li>Update</li>
	<li>Clear the cache</li>
</ol>

The <script> in the input is four escaped characters in the output. The ampersand in AT&T is &amp;. Both are what a reader will see as the original text, and neither is markup.

Pitfalls

Escape the ampersand first. & must be replaced before < and >, or the &lt; you just produced becomes &amp;lt; and the reader sees the escape rather than the character. It is a one-line ordering bug and it is in a lot of hand-rolled converters.

Escaping only < and > is not enough. A stray & left in the output is interpreted by the browser, so AT&T can render as AT&T today and break the moment something re-encodes the page. Escape all five characters.

<br /> is not a paragraph. Two sentences joined with a line break are one paragraph to a screen reader, to a search engine and to CSS. Turn line breaks off for prose and let the blank lines do the work.

Autolinking is a security decision. A link built from unescaped text can close the href attribute and add an event handler. Here the pattern runs after escaping and matches http and https only, so javascript: and data: URLs never become links.

Add nofollow for text you did not write. rel="noopener" is the default and is about window handles. If the text came from a visitor, the rel you want is noopener nofollow ugc.

This is not Markdown. Bold, italics, headings, links with text and code fences are not recognised, on purpose: a converter that half-implements Markdown is worse than one that does paragraphs properly. There is a Markdown tool on this site for Markdown.

Trailing whitespace disappears. Lines are trimmed, because a plain-text file’s trailing spaces are an accident rather than a meaning. The exception is a Markdown two-space line break, which this tool does not implement anyway.

Compatibility

Everything runs in the browser: nothing is uploaded and nothing is stored, which matters when the text is a customer email or an unpublished draft.

The output is plain HTML with no classes and no wrapper, so it drops into a WordPress block, a template, an email builder or a static site without bringing anything with it. <br /> is written in the self-closing form, which is valid in both HTML and XHTML; if your linter prefers <br>, both parse identically.

Input is capped at 100,000 characters. Above that, convert it in sections.

This is not nl2br. nl2br adds a <br> after every newline and leaves the paragraphs undivided; WordPress’s wpautop is closer, and it also does not escape, because it expects content that is already trusted.

Frequently asked questions

Should I turn line breaks on or off?
Off for prose: let blank lines make paragraphs and let the text wrap. On for anything where the line endings are meaningful, such as an address, a poem or a list you do not want marked up as a list.
Why is my apostrophe &#039;?
Because a bare apostrophe inside a single-quoted attribute closes it, and escaping it everywhere is the safe rule. It renders as an apostrophe.
Can it produce Gutenberg blocks?
Not directly. Paste the HTML into a Custom HTML block, or use the HTML-to-blocks converter on this site, which turns markup into real block comments.
Does it handle smart quotes and dashes?
It leaves them exactly as they are in your text. If your text has straight quotes, the output has straight quotes: replacing them is a decision about the writing, not about the markup.
What about tables?
Not recognised. A plain-text table is hard to distinguish from a paragraph with tabs in it, and guessing wrong produces a mess. Write the <table> by hand or use the Markdown tool.
Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.