Plugin: Copy as HTML [v1.4.2, 2025-11-15]

Joplin Copy as HTML Plugin :clipboard:

NOTE : This plugin was created entirely with AI tools

This plugin allows you to copy selected text in the markdown editor as either HTML or plain text (with markdown formatting characters removed).

The primary use case is copying text from Joplin and pasting formatted text into other apps that support HTML formatting (e.g. pasting text into an Outlook email). A plain text fallback is provided for scenarios where you need to paste text into an application that supports neither HTML formatting nor markdown.

Copy as HTML

"Copy selection as HTML" is provided as a right click context menu option and as a keyboard shortcut (ctrl + shift + c by default).

This will populate the clipboard's text/html category with the HTML formatted text.

NOTE
In Joplin 3.5.4 and newer, it will populate both text/html and text/plain (allowing you to paste either formatted or plain text).

Embed images as base64

By default, the plugin will embed any images as base64 in the text/html output, allowing you paste text + images into external applications. However, this can be disabled in the plugin's settings.

This will work with both markdown image embeds and the html <img> embeds that you get when resizing images via joplin's rich text editor.

Download and embed remote images as base64

If you enable this option (along with "Embed images as base64"), remote image embeds will be downloaded and embedded as base64 (making the images viewable without internet access).

Export as fragment or full HTML document

When you copy text from Joplin's markdown viewer (or export the note to HTML), there is a lot of styling applied which can sometimes cause issues pasting text into other editors (e.g. if you copy from the markdown viewer, your joplin theme's background color may be pasted).

HTML Fragment

By default, the plugin will populate the clipboard with an HTML fragment, e.g:

<html>
    <body>
        <!--StartFragment-->
        <h2>Test Heading</h2>
        <p>Test paragraph 1</p>
        <p>Test paragraph 2</p>
        <!--EndFragment-->
    </body>
</html>

This is similar to what you get when copying from Joplin's TinyMCE rich text editor (semantic markup, no css styling). Any styling will be determined by the application you're pasting the text into.

Full HTML Document

Optionally, you can enable the setting "Export as full HTML document".

This will wrap the HTML fragment in a full HTML document with CSS styling. A default (minimal) css stylesheet is provided. The default stylesheet is only used if no custom stylesheet is provided and the "Export as full HTML document" setting is enabled.

To use your own stylesheet, create a file called copy-as-html-user.css in your Joplin profile directory. To locate your Joplin profile directory, open Joplin and click Help | Open profile directory.

Optional markdown syntax

The plugin will adhere to Joplin's settings for whether or not to render:

  • Soft Breaks
  • Typographer
  • Linkify
  • ==mark==
  • Footnotes
  • Table of Contents
  • ~sub~
  • ^sup^
  • Deflist
  • Abbreviation
  • Markdown Emoji
  • ++Insert++
  • Multimarkdown Table

NOTE
Mermaid/Math are not supported, they will render as plain text (code).

Freehand Drawing/Excalidraw

These embed the drawings as joplin image resources (svg), and the plugin will embed them as base64 as it does other images.

SVG images may have compatibility issues with certain editors/email clients, so by default the plugin will convert svg images to png when embedding images, however this can be disabled in the plugin settings.

Github Alerts

Github Alert syntax, (e.g. >[!NOTE]) is supported via the markdown-it-github-alerts plugin. In order for github alerts to be rendered nicely, you must be using the Full document mode with CSS styling targeting the .markdown-alert classes. The default stylesheet contains styling for github alerts, example:

Copy as Plain Text

"Copy selection as Plain Text" is provided as a right click context menu option and as a keyboard shortcut (ctrl + alt + c by default).

This will strip markdown formatting characters, backslash escapes, and image embeds from the source markdown and populate it as text/plain in the clipboard, for scenarios where you need to paste into an app that supports neither HTML formatting or markdown.

List leaders and nested list indentation will be maintained (these are normally lost when copying from the markdown viewer or rich text editor).

Customizing plain text output

The following options are provided to preserve specific markdown formatting in the text/plain output:

  • Preserve superscript characters (^TEST^)

  • Preserve subscript characters (~TEST~)

  • Preserve emphasis characters (*TEST* or _TEST_)

  • Preserve bold characters (**TEST** or __TEST__)

  • Preserve heading characters (## TEST)

  • Preserve strikethrough characters (~~TEST~~)

  • Preserve horizontal rule (---)

  • Preserve highlight characters (==TEST==)

  • Preserve insert characters (++TEST++)

The following options are provided for external hyperlinks (only impacts markdown links containing http/https URL):

  • Title - Displays link title only (default).

  • URL - Displays link URL only.

  • Markdown Format - Displays full markdown link formatting with title and URL.

The following options are provided for indentation style:

  • Tabs
  • (4) Spaces (default)

Markdown emoji

Copy as Plain Text supports the markdown-it emoji plugin, so emoji such as :white_check_mark: will be displayed in the plain text output. This can be disabled if desired via the Display emojis setting.

Known Issues

  • The plugin's keyboard shortcuts sometimes don't work on cold start of Joplin, can be fixed by toggling editors or going to Tools | Options | Keyboard Shortcuts and back.
3 Likes

Changes from v1.0.3 to v1.0.6:

  • Replaced ugly error dialogue that appeared when you activated the plugin without any text selected with an info toast
  • Updated the copy successful toast message to use success toast type
  • Gracefully handle invalid resource links when embedding images. Now, the copy will still succeed and any invalid images will be replaced with placeholder text (Resource ID “:/resource-id-here” could not be found.)
  • Remove &nbsp; characters from text/plain output

v1.0.8

Significant changes to the copy as plaintext feature:

1. The plugin now uses markdown-it with a custom renderer to extract the plaintext instead of the remove-markdown package. This allows for much greater flexibility in customizing the plain text output.

2. The plugin now has several options to preserve a subset of markdown formatting in the plaintext output.

In my case, the main thing I care about in the plaintext output is getting rid of those damned backslash escape characters, I don't mind having the basic markdown formatting like bold, italics, etc... so there are now options to preserve these:

  • Preserve superscript characters (^TEST^)
    If enabled, ^TEST^ will remain ^TEST^ in plain text output.

  • Preserve subscript characters (~TEST~)
    If enabled, ~TEST~ will remain ~TEST~ in plain text output.

  • Preserve emphasis characters (*TEST* or _TEST_)
    If enabled, *TEST* or _TEST_ will remain as-is in plain text output.

  • Preserve bold characters (**TEST** or __TEST__)
    If enabled, **TEST** or __TEST__ will remain as-is in plain text output.

  • Preserve heading characters (## TEST)
    If enabled, ## TEST will remain as-is in plain text output.

3. Nicer tables. Instead of exporting the raw markdown table, you'll get a properly aligned table, e.g:

TestColumn1  TestColumn2  TestColumn3
-----------  -----------  -----------
A            B            C          
D            E            F          

3. Paragraph breaks are consistently maintained (e.g. below headings and below code blocks).

v1.0.9

  • [copy as plaintext] Fixed broken ordered list numbering when there were nested unordered lists between ordered list entries
  • [copy as plaintext] Maintain indentation of nested list items
1 Like

v1.0.11

  • [Copy as HTML] width/height properties are now preserved in the extracted HTML, so image sizes are retained when copying html <img> formatted images.
  • [Copy as Plain Text] - Removed logic to remove html <img> elements from the plain text output, it was causing various issues (and if your selection contains both text + images you probably want to copy as HTML anyway).
  • [Copy as Plain Text] regex for removing nbsp from plain text output was much too greedy, adjusted so it only removes nbsp if on its own line

v1.0.12

  • [Copy as Plain Text] Completely removed regex to remove nbsp... it's no longer needed with the markdown-it implementation (since nbsp is no longer shown as literal text in the text/plain output), and removing it allows us to maintain whitespace created by the rich text editor (nbsp on its own line)

v1.0.13

  • [Copy as Plain Text] Restored functionality to remove html <img> embeds from text/plain output, now works without touching code blocks using the same method that was used for removing backslash escapes

v1.0.14

  • [Copy as Plain Text] don't collapse whitespace inside code blocks
1 Like

Thanks for this plugin :+1:

v1.0.15

  • [Copy as Plain Text] New Feature: Add setting for hyperlink behavior (Link Title, URL, or Markdown format)
  • No other user facing changes, code was significantly cleaned up and refactored

v1.0.16

  • [Copy as Plain Text] Fix space below block quotes
  • No other user facing changes, code was significantly re-factored (split into multiple files, implement type safety throughout, improve error handling, add input and configuration validation)

v1.0.18

  • [Copy as HTML] - fix spacing issues with indented block elements followed by horizontal rules
  • [Copy as HTML] - remove joplin specific onclick markup from final html fragment
  • [Copy as Plain Text] - also handle ++insert++ and ==mark== in plaintext output
  • More code refactoring and cleanup, improved error handling

I'll chill out with the rapid updates for now :D, I think the plugin is in a good state

2 Likes

Thank you for this great and useful plugin. But, I’ve got a problem. It is a general problem, not just here. I’m using Windows and Essential Pim for email also Windows. Windows uses a cr and a LF at the end of lines. when I paste, the html I get 2 lines between each paragraph or whenever there is a single line break. This happens a lot, not only with your plugin.

Does anyone know a way to handle this?

Does it only happen when pasting into the EssentialPIM app?

The behavior of pasting formatted text can vary quite a bit depending on the application you're pasting into. I mainly test the plugin with Gmail and Outlook and haven't seen any issues with extra line spacing when pasting.

The plugin currently generates just a semantic HTML fragment, e.g:

<html>
   <body>
      <!--StartFragment-->
      <h2 id="test-heading">Test Heading</h2>
      <p>Test paragraph 1</p>
      <p>Test paragraph 2</p>
      <!--EndFragment-->
   </body>
</html>

There is no styling provided, so any paragraph spacing, etc... should be controlled by the app you're pasting into (and this is most likely some kind of quirk with the essentialPIM app).

In an upcoming update, I'm adding support for the plugin to generate a full HTML document with a user supplied stylesheet, which could allow you to set specific paragraph spacing with CSS which might potentially help.

However, if essentialPIM is generating actual line breaks (<br>) when pasting, then css styling might not change the behavior.

You could try using the plugin's "Copy as Plain Text" option to copy the plain text- that would likely paste without any odd behavior (but you would lose any rich text formatting).

I did some testing, not much but some. Windows 11

I used 1. Windows built-in notepad
2. Notepad ++

3. and EPIM.

Copied a joplin note with some headers and lists and a bold face.

To EPIM

If I copy as html, it copies into epim with the extra blank lines. All formatting correct.

If I copy as plain text, then there is no formatting and no extra blank lines.

So it seems that there is a problem with my clipboard and how your copy as html handles the clipboard. Of the three programs, only epim recognizes that there exists anything to paste using that.

If I copy as html into notepad though I get a notice saying I have copied to HTML, nothing pastes at all. There is nothing in the clipboard I can find. Copy as plain text works as expected. Plain copy works as expected.

If I copy into notepad++

plain copy works fine (windows ctrl-c and ctrl-v)

copy as HTML does nothing. No copy. nothing in clipboard

copy as plain text works

yeah copying to HTML and then pasting as plain text doesn't work with the plugin currently,

Commonly when you copy formatted text from a web browser or rich text editor, the clipboard will be populated with both the text/html clipboard category (HTML formatted text) and the text/plain clipboard category (plain text).

This makes it so that if you paste into an app that supports rich text, the app knows to use text/html and paste the formatted text

And if you paste into an app that only supports plaintext (e.g. notepad), it pastes the contents of the text/plain category instead.

There's also a shortcut supported by most apps (ctrl + shift + v) to force pasting the text/plain instead of text/html

This is what I originally wanted to do with this plugin, but I ran into an issue which (I think, not 100% sure) is a limitation with the Joplin plugin API:

If you try to write both html and text to the clipboard at the same time ( using joplin.clipboard.writeHtml() and joplin.clipboard.writeText() ), you only get the HTML in the clipboard, so I resorted to making them separate commands ("Copy selection as HTML" and "Copy selection as Plain Text").

I might revisit that in the future, I would love it if I could get that to work as it's more intuitive/standard behavior.

I frequently have the same problem with extra blank lines when I copy parts of webpages or AI answers from various AI bots.

FYI—I tried copying directly into LibreOffice Writer, and it worked perfectly. However, the issue with extra blank lines in my email part of EssentialPIM occurs not only with your app but frequently with chatbots and selections from web pages. I’ll make a feature request to have an option that removes extra blank lines, perhaps functioning as a search and replace. However, I don’t even get a source code for what actually gets inserted into my email after the paste operation.

v1.1.0

This is a pretty big release! at this point I've been able to implement every feature that I originally set out to (and more):

Copy as HTML

Copy as Full Document

The plugin now allows you to copy as a full HTML document with your own custom CSS styling

A default (minimal) css stylesheet is provided. The default stylesheet is automatically used if no custom stylesheet is provided and the "Export as full HTML document" setting is enabled.

To use your own stylesheet, create a file called copy-as-html-user.css in your Joplin profile directory. To locate your Joplin profile directory, open Joplin and click Help | Open profile directory.

Settings adherence

When Copying to HTML, elements that are rendered now adhere to nearly every setting from Joplin's Markdown tab (basically, math and diagrams are the only things not supported):

  • Soft Breaks
  • Typographer (you can thank this plugin for making me go down this rabbit hole xD)
  • Linkify
  • ==mark==
  • Footnotes
  • Table of Contents
  • ~sub~
  • ^sup^
  • Deflist
  • Abbreviation
  • Markdown Emoji
  • ++Insert++
  • Multimarkdown Table

Other Changes

  • (non-image) Joplin Resource links will now only display the link title.

Copy as Plain Text

  • Setting to display markdown emojis. Emoji shortcodes will be completely hidden if disabled, or Emoji unicode characters will be displayed if enabled (default).

  • Setting to preserve horizontal rule. Also, there will now be whitespace where the horizontal rule was if not preserving them.
  • Setting to preserve strikethrough (it was pretty much the only bit of common mark formatting missing, so why not lol)

v1.1.1 - v1.1.6

  • [Copy as HTML] - Fix Edge case where <img> wasn't removed when image embedding was disabled
  • [Copy as HTML] - Configure Linkify so it only linkifies http(s) URLs and mailto links
  • [Copy as HTML] - Fix potential memory leak
  • [Copy as HTML] - Improved font stack in default stylesheet
  • [Copy as HTML] - Remove no longer used @joplin/renderer dependency to reduce plugin size
  • [Copy as HTML/Copy as Plain Text] Improve messaging when plugin is invoked from rich text editor
  • [Copy as Plain Text] - Feature: Add setting for Tabs or (4) Spaces for Indentation
  • [Copy as Plain Text] - Small reliability improvements

v1.1.7

  • Add unit tests
  • simplify attribute preservation code by not preserving "style" attribute (which normally wouldn't be present in joplin image embeds)
  • [Copy as Plain Text] - Move markdown preservation settings under "advanced" to declutter settings
  • dynamically register context menu, so context menu entry only shows in markdown editor context menu

v1.1.8

  • Also preserve image alt text when preserving image dimensions

v1.1.9

  • Remove jsdom dependency, significantly reducing plugin size (3mb > 260kb)

v1.1.12

  • [Copy as Plain Text] - Fixed inconsistent behavior when not preserving horizontal rules (depending on structure of the document, it would sometimes leave whitespace where the HR was, sometimes wouldn't), it now consistently leaves whitespace where the HR was.
  • [Copy as HTML] - Add support for github alerts (e.g. > [!NOTE]). They will now be rendered as divs (with class of .markdown-alert and .markdown-alert-title) via the markdown-it github alerts plugin. This allows CSS styling to display them properly (see below example).

NOTE: Rendering github alerts like the below example requires CSS styling (so only works when full document setting is enabled). The default stylesheet has been updated to provide styling for github alerts (and the styling for standard block quotes is updated for consistency).

image

v1.1.13

  • fix issue where (when linkify is enabled) multiple bare hyperlinks on a single line were linkified into a single link 353404d

v1.1.14

  • [Copy as HTML] - Security: Sanitize HTML in post processing phase

v1.1.15

Copy as HTML

  • Feature: Download and embed remote images as base64 when copying as HTML (optional, can be enabled in settings)
  • Fix pre-existing issue with inconsistent behavior of remote images when "Embed images as base64" was disabled (html format remote images were being removed, markdown format weren't). Since remote image embeds can typically be displayed without base64 encoding, I don't think it makes sense to remove then, so adjusted logic to always keep remote image embeds, and only remove Joplin resources.
  • Add markdown-it anchor plugin (needed for toc-done-right to work properly)
  • Fixed some minor regex issues (use case insensitive regex for alt attribute)
  • Update default stylesheet to fix issues with padding/margin at the bottom of block quotes and github alerts if they contained a list

Copy as HTML/Copy as Plain Text

  • Fix issue where debug logging option to troubleshoot plugin loading was only hooked up to loading of the github alerts plugin, now logs all plugin loading success/failures when enabled
  • Update dependencies

v1.2.0

  • Massively simplified image embedding logic (it was a giant hack leftover from fighting @joplin-renderer stripping the image size attributes... now that the plugin uses markdown-it directly html <img> attributes are left alone (and we do the HTML sanitization afterwards) so there's no need to convert them to markdown and then back to html with preserved attributes).
  • Resources (local and remote) are now fetched concurrently, so should have improved performance when embedding many images
  • fix bug where remote image embedding didn't work with markdown embeds that included "title"
  • fix bug where markdown embeds with title weren't removed from final HTML when image embedding is disabled
  • improve code block protection regex to also catch nested code blocks

v1.2.1

  • Further improvements to image embedding logic, now parses markdown with markdown-it to get image resources instead of complex regex. Should handle all edge cases (code blocks, etc...) more reliably.
  • Normalization of raw html images so top-level raw HTML images render like separate block elements, matching the “one image per line” behavior you get with Markdown images

v1.2.2 - 1.2.4

  • Rewrote plain text renderer: Separated markdown parsing from formatting for easier maintenance/testing.
  • Improved max image size handling when downloading remote images
  • Improve handling of failed remote image downloads

v1.2.5

  • Simplify image embedding so that markdown and html image embeds are handled the same way (replaced in DOM post processing)
  • Simplified error handling for image embedding failures (now consistent messaging for markdown and html image embeds)

v1.2.6

  • Removed redundant logging
  • Tightened DOMPurify config
  • Small adjustment to default stylesheet (use Cascadia Mono instead of Cascadia Code)
  • Replaced unmaintained markdown-it plugins (task lists and toc) with better maintained versions
1 Like

v1.3.0

  • The Copy as HTML function now populates the clipboard with both text/html and text/plain (so if you're pasting into an app that supports rich text, html is pasted by default, but you can use ctrl + shift + v to paste plain text if needed).
  • NOTE: This functionality requires Joplin 3.5.4 or newer. If you're running an older joplin version, it will work as it did previously (populating only text/html).
  • The separate Copy as Plain Text function is still available and works as it did before.

v1.3.1 - 1.3.2

  • Update dependencies
  • Simplify image embedding error handling
  • Simplified markdown-it plugin loading
  • Simplified clipboard handling
  • Improvements to image embedding error handling/memory usage

v1.4.0

  • Feature: Convert SVG images to PNG when embedding images (enabled by default due to spotty svg support in email clients, can be disabled in settings).
  • Fix: Emojis not being included in tables in plain text output when display emojis is enabled.
  • Other: Refactored resource fetching code and debug logging

v 1.4.1

  • Improve quality of rasterized svgs (render at 2x size and then apply original dimensions in html img attributes)
  • Refactor DOM processing and improve SVG handling

v1.4.2

  • [Copy as Plain Text] - strip HTML from plan text output (e.g. This is a <span style="color: rgb(186, 55, 42);">test <span style="color: rgb(0, 0, 0);">of colored text</span></span> becomes This is a test of colored text
1 Like