{"id":4153,"date":"2024-10-11T10:55:42","date_gmt":"2024-10-11T15:55:42","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=4153"},"modified":"2024-10-11T17:05:00","modified_gmt":"2024-10-11T22:05:00","slug":"handling-paste-events-in-javascript","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/handling-paste-events-in-javascript\/","title":{"rendered":"Handling Paste Events in JavaScript"},"content":{"rendered":"\n<p>Welcome to the third and final post in the series. In the&nbsp;<a href=\"https:\/\/frontendmasters.com\/blog\/reading-from-the-clipboard-in-javascript\/\">first article<\/a>, I explained how JavaScript can read from the user&#8217;s clipboard. In the&nbsp;<a href=\"https:\/\/frontendmasters.com\/blog\/writing-to-the-clipboard-in-javascript\/\">last article<\/a>, I explained the opposite, writing to the user&#8217;s clipboard. Now I&#8217;m going to demonstrate how to add basic &#8220;paste event&#8221; handling in your web app. Luckily, much of what we learned in the past two articles will come in handy as the &#8216;shape&#8217; of the data will be the same.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/reading-from-the-clipboard-in-javascript\/\">Reading from the Clipboard in JavaScript<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/writing-to-the-clipboard-in-javascript\/\">Writing to the Clipboard in JavaScript<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/handling-paste-events-in-javascript\/\">Handling Paste Events in JavaScript<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"listening-for-the-event\">Listening for the Event<\/h2>\n\n\n\n<p>If you&#8217;ve done anything at all with JavaScript and events you can probably guess the name of the event we&#8217;ll use,\u00a0<code>paste<\/code>. I love language features, APIs, SDKs, etc where my natural guess about how something is done works! <em>Where<\/em> you listen for that event will depend on your use, but for our purposes, we&#8217;ll make it easy and add a listener on the\u00a0<code>window<\/code>\u00a0object like so:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">window<\/span>.addEventListener(<span class=\"hljs-string\">'paste'<\/span>, e =&gt; {}, <span class=\"hljs-literal\">false<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That&#8217;s the easy part. Note that as with most event-related handlers, if you want to block the default action, for example, if the user pasted into a form field, you would use <code>e.preventDefault()<\/code>. One example of this (and to be clear, I&nbsp;<em>despise<\/em>&nbsp;this example) are forms asking for confidential information like bank account numbers. The form will disable pasting information into the form field. Again, I&nbsp;<em>really<\/em>&nbsp;don&#8217;t like this, so if you do make use of this, please consider using a&nbsp;<code>title<\/code>&nbsp;field to provide information to the user. Here&#8217;s an example.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_qBeaYrZ\" src=\"\/\/codepen.io\/anon\/embed\/qBeaYrZ?height=450&amp;theme-id=47434&amp;slug-hash=qBeaYrZ&amp;default-tab=js,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed qBeaYrZ\" title=\"CodePen Embed qBeaYrZ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"working-with-the-event\">Working with the Event<\/h2>\n\n\n\n<p>So you&#8217;re listening for the paste event and want to do something with it, how do you begin? When the event fires, it contains a&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/ClipboardEvent\/clipboardData\"><code>clipboardData<\/code><\/a>&nbsp;object. There are two main things we can do with this object:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Read textual data from it using a method,&nbsp;<code>getData<\/code><\/li>\n\n\n\n<li>Check for a pasted&nbsp;<em>file<\/em>&nbsp;using the&nbsp;<code>files<\/code>&nbsp;property<\/li>\n<\/ul>\n\n\n\n<p>Let&#8217;s take a quick look at working with text.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"getting-text-of-a-pasted-event\">Getting Text of a Pasted Event<\/h2>\n\n\n\n<p>The&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/DataTransfer\/getData\"><code>getData<\/code><\/a>&nbsp;method accepts one attribute, the format of the data to retrieve.<\/p>\n\n\n\n<p>For example, to read the text of the clipboard:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> pastedText = e.clipboardData.getData(<span class=\"hljs-string\">'text\/plain'<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And HTML:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> pastedText = e.clipboardData.getData(<span class=\"hljs-string\">'text\/html'<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The HTML version gets a bit&#8230; interesting. Let&#8217;s build a quick application to let you test this quickly. First, some HTML that includes radio buttons to let you select how to handle the paste event and an empty <code>&lt;div&gt;<\/code> for the data:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Pasted Data<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">for<\/span>=<span class=\"hljs-string\">\"textplain\"<\/span>&gt;<\/span>View text\/plain<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"radio\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"type\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"textplain\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"text\/plain\"<\/span> <span class=\"hljs-attr\">checked<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">for<\/span>=<span class=\"hljs-string\">\"texthtml\"<\/span>&gt;<\/span>View text\/html<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"radio\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"type\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"texthtml\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"text\/html\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"pasteDump\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In our JavaScript, we&#8217;ll listen for changes to the radio button as a way to determine how to handle the paste event. The paste event handler itself will call&nbsp;<code>getData()<\/code>&nbsp;and log it out to the <code>&lt;div&gt;<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> type = <span class=\"hljs-string\">'text\/plain'<\/span>;\n\n<span class=\"hljs-built_in\">document<\/span>.querySelectorAll(<span class=\"hljs-string\">'input&#91;name=type'<\/span>).forEach(<span class=\"hljs-function\"><span class=\"hljs-params\">i<\/span> =&gt;<\/span> {\n  i.addEventListener(<span class=\"hljs-string\">'change'<\/span>, e =&gt; {\n    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'click'<\/span>, e.target.value);\n    type = e.target.value;\n  },<span class=\"hljs-literal\">false<\/span>);\n});\n\n<span class=\"hljs-built_in\">window<\/span>.addEventListener(<span class=\"hljs-string\">'paste'<\/span>, e =&gt; {\n  <span class=\"hljs-keyword\">let<\/span> dump = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'#pasteDump'<\/span>);\n\t\n  <span class=\"hljs-keyword\">let<\/span> data = e.clipboardData.getData(type);\n  <span class=\"hljs-built_in\">console<\/span>.log(data);\n  dump.innerHTML = data;\n}, <span class=\"hljs-literal\">false<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, you can paste text into the demo and see the different results in your browser console:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_RwXGyqx\" src=\"\/\/codepen.io\/anon\/embed\/RwXGyqx?height=450&amp;theme-id=47434&amp;slug-hash=RwXGyqx&amp;default-tab=js,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed RwXGyqx\" title=\"CodePen Embed RwXGyqx\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>For &#8216;plain\/text&#8217;, you see what I think you would expect. If you go to a random web page, lets say the&nbsp;<a href=\"https:\/\/frontendmasters.com\/blog\/reading-from-the-clipboard-in-javascript\/\">first article<\/a>&nbsp;in this series, and select from the title to the first paragraph:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"832\" height=\"508\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot1.png?resize=832%2C508&#038;ssl=1\" alt=\"\" class=\"wp-image-4159\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot1.png?w=832&amp;ssl=1 832w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot1.png?resize=300%2C183&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot1.png?resize=768%2C469&amp;ssl=1 768w\" sizes=\"auto, (max-width: 832px) 100vw, 832px\" \/><\/figure>\n\n\n\n<p>And the paste, you get:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Reading from the Clipboard in JavaScript July 31, 2024 Browsers have excellent support for reading and writing the user\u2019s clipboard, and this opens up possibilities for better, and more native like experiences on the web. On websites that use these APIs for helpful features, it feels natural to the user. On sites where it isn\u2019t supported, it almost feels like a bug. In this series of articles, I\u2019m going to demonstrate how to work with the clipboard.<\/pre>\n\n\n\n<p>I&#8217;ll note that the line breaks were preserved, but are lost when rendered in HTML. If you wanted, you could do a string replacement for&nbsp;<code>\\n<\/code>&nbsp;for&nbsp;<code>&lt;br&gt;<\/code>&nbsp;to more accurately render the text.<\/p>\n\n\n\n<p>The HTML version is a bit&#8230; different:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"738\" height=\"293\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot2.png?resize=738%2C293&#038;ssl=1\" alt=\"\" class=\"wp-image-4160\" style=\"width:594px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot2.png?w=738&amp;ssl=1 738w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/shot2.png?resize=300%2C119&amp;ssl=1 300w\" sizes=\"auto, (max-width: 738px) 100vw, 738px\" \/><\/figure>\n\n\n\n<p>As you can see, it tried to accurately, kinda, represent the HTML from the selection. If you open up your console, you&#8217;re presented with something monstrous:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-comment\">&lt;!--StartFragment--&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"gradient-style-text\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"box-sizing: border-box; font-family: <span class=\"hljs-symbol\">&amp;quot;<\/span>Mona Sans<span class=\"hljs-symbol\">&amp;quot;<\/span>, system-ui, -apple-system, BlinkMacSystemFont, <span class=\"hljs-symbol\">&amp;quot;<\/span>Segoe UI<span class=\"hljs-symbol\">&amp;quot;<\/span>, Roboto, Oxygen, Ubuntu, Cantarell, <span class=\"hljs-symbol\">&amp;quot;<\/span>Open Sans<span class=\"hljs-symbol\">&amp;quot;<\/span>, <span class=\"hljs-symbol\">&amp;quot;<\/span>Helvetica Neue<span class=\"hljs-symbol\">&amp;quot;<\/span>, sans-serif; white-space: balance; letter-spacing: 0px; margin: 0px; line-height: 1.1; font-variation-settings: <span class=\"hljs-symbol\">&amp;quot;<\/span>wght<span class=\"hljs-symbol\">&amp;quot;<\/span> 900, <span class=\"hljs-symbol\">&amp;quot;<\/span>wdth<span class=\"hljs-symbol\">&amp;quot;<\/span> 125; font-size: var(--font-size-xxl); word-break: break-word; color: rgb(255, 255, 255); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(0, 0, 0); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; view-transition-name: header-3136;\"<\/span>&gt;<\/span>Reading from the Clipboard in JavaScript<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">time<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"block-time\"<\/span> <span class=\"hljs-attr\">datetime<\/span>=<span class=\"hljs-string\">\"2024-07-31\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"box-sizing: border-box; font-family: var(--font-family-monospace); text-transform: uppercase; font-size: var(--font-size-xsm); letter-spacing: 0.3rem; margin: 0px 0px 2rem; display: block; color: rgb(255, 255, 255); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-align: start; text-indent: 0px; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(0, 0, 0); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; view-transition-name: article-time-3136;\"<\/span>&gt;<\/span>July 31, 2024<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">time<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"article-content\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"box-sizing: border-box; font-size: var(--font-size-md); color: rgb(255, 219, 219); position: relative; word-break: break-word; overflow-wrap: break-word; font-family: <span class=\"hljs-symbol\">&amp;quot;<\/span>Mona Sans<span class=\"hljs-symbol\">&amp;quot;<\/span>, system-ui, -apple-system, BlinkMacSystemFont, <span class=\"hljs-symbol\">&amp;quot;<\/span>Segoe UI<span class=\"hljs-symbol\">&amp;quot;<\/span>, Roboto, Oxygen, Ubuntu, Cantarell, <span class=\"hljs-symbol\">&amp;quot;<\/span>Open Sans<span class=\"hljs-symbol\">&amp;quot;<\/span>, <span class=\"hljs-symbol\">&amp;quot;<\/span>Helvetica Neue<span class=\"hljs-symbol\">&amp;quot;<\/span>, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.64px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(0, 0, 0); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"box-sizing: border-box; margin-top: 0px; margin-bottom: 2.2rem;\"<\/span>&gt;<\/span>Browsers have excellent support for reading and writing the user\u2019s clipboard, and this opens up possibilities for better, and more<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"box-sizing: border-box; font-variation-settings: <span class=\"hljs-symbol\">&amp;quot;<\/span>wght<span class=\"hljs-symbol\">&amp;quot;<\/span> 400, <span class=\"hljs-symbol\">&amp;quot;<\/span>wdth<span class=\"hljs-symbol\">&amp;quot;<\/span> 100, <span class=\"hljs-symbol\">&amp;quot;<\/span>slnt<span class=\"hljs-symbol\">&amp;quot;<\/span> -10; font-style: normal; color: rgb(250, 162, 162); margin-right: 0.1rem;\"<\/span>&gt;<\/span>native like<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>experiences on the web. On websites that use these APIs for helpful features, it feels natural to the user. On sites where it\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"box-sizing: border-box; font-variation-settings: <span class=\"hljs-symbol\">&amp;quot;<\/span>wght<span class=\"hljs-symbol\">&amp;quot;<\/span> 400, <span class=\"hljs-symbol\">&amp;quot;<\/span>wdth<span class=\"hljs-symbol\">&amp;quot;<\/span> 100, <span class=\"hljs-symbol\">&amp;quot;<\/span>slnt<span class=\"hljs-symbol\">&amp;quot;<\/span> -10; font-style: normal; color: rgb(250, 162, 162); margin-right: 0.1rem;\"<\/span>&gt;<\/span>isn\u2019t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\u00a0supported, it almost feels like a bug. In this series of articles, I\u2019m going to demonstrate how to work with the clipboard.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-comment\">&lt;!--EndFragment--&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This reminds me quite a lot of what Word documents exported to HTML looked like. Visually fine, but a source that would make your head spin.<\/p>\n\n\n\n<p>If your curious how this handles&nbsp;<em>non<\/em>-text data: it depends.<\/p>\n\n\n\n<p>Right clicking on an image and pasting it in returns nothing if the type is &#8216;text\/plain&#8217;, but with &#8216;text\/html&#8217;, you get:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-comment\">&lt;!--StartFragment--&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">'https:\/\/www.raymondcamden.com\/images\/avatar3.jpg'<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">'Raymond Camden'<\/span>\/&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span><span class=\"hljs-comment\">&lt;!--EndFragment--&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In this case, I copied an image from my blog. While this works, there&#8217;s a better way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"getting-files-from-the-clipboard\">Getting Files from the Clipboard<\/h2>\n\n\n\n<p>So what happens when you try to paste binary data, or let&#8217;s even say a file you copied from your machine? These end up in the&nbsp;<code>clipboardData.files<\/code>&nbsp;property. This is an array-like&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/FileList\">FileList<\/a>&nbsp;object which matches what you get from an input form field with&nbsp;<code>type=file<\/code>&nbsp;or when you drag and drop into the browser. Because of this, code you may have used before can be used again, which is handy.<\/p>\n\n\n\n<p>One simple method for handling images is using a&nbsp;<code>FileReader<\/code>&nbsp;object, reading in the file as a data URL, and then adding it to the DOM. Let&#8217;s look at an example of that.<\/p>\n\n\n\n<p>First, our simple HTML:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Pasted Images<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  Paste an image into the browser.\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"preview\"<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Notice the &#8217;empty&#8217; image. This is what we&#8217;ll use for the preview. Now the JavaScript:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> img = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'#preview'<\/span>);\n\n<span class=\"hljs-built_in\">window<\/span>.addEventListener(<span class=\"hljs-string\">'paste'<\/span>, e =&gt; {\n\n  <span class=\"hljs-keyword\">if<\/span>(e.clipboardData.files.length) {\n    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'handle a file'<\/span>);\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/*\n    Files can be 2 or more, but we'll focus on 1 for img preview\n    *\/<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    <span class=\"hljs-keyword\">let<\/span> file = e.clipboardData.files&#91;<span class=\"hljs-number\">0<\/span>];\n    <span class=\"hljs-keyword\">if<\/span> (file.type.startsWith(<span class=\"hljs-string\">'image\/'<\/span>)) {\n      previewImage(file);\n    }\n }\n\n}, <span class=\"hljs-literal\">false<\/span>);\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">previewImage<\/span>(<span class=\"hljs-params\">file<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">let<\/span> reader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n\n  reader.onload = <span class=\"hljs-function\"><span class=\"hljs-params\">e<\/span> =&gt;<\/span> {\n    img.src = e.target.result;\n  }\n\n  reader.readAsDataURL(file);   \n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If the pasted event contains file, we can check the mimetype of each (although in this case, to keep things simple we&#8217;ll focus on one), and if it is an image, run&nbsp;<code>previewImage<\/code>, which handles reading and converting the data into a URL. You can try this version below:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_VwoKENq\" src=\"\/\/codepen.io\/anon\/embed\/VwoKENq?height=450&amp;theme-id=47434&amp;slug-hash=VwoKENq&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed VwoKENq\" title=\"CodePen Embed VwoKENq\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Just as when we were <a href=\"https:\/\/frontendmasters.com\/blog\/writing-to-the-clipboard-in-javascript\/\"><em>writing <\/em>to the clipboard<\/a> we had APIs like <code>writeText<\/code> and <code>write<\/code> where we had to be cognizant of the <em>type<\/em> we were writing, the pasting APIs have events with <code>clipboardData<\/code> in them too where we can get the data out in potentially a type of our preference. It is up to you to react to these paste events in a way with the best UX and accessibility you can muster. And remember: don&#8217;t block pasting as faux security measure!<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/reading-from-the-clipboard-in-javascript\/\">Reading from the Clipboard in JavaScript<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/writing-to-the-clipboard-in-javascript\/\">Writing to the Clipboard in JavaScript<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/handling-paste-events-in-javascript\/\">Handling Paste Events in JavaScript<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This concludes our three-part series on working with clipboard data. With pasting, we have some control over the type of data we want to use.<\/p>\n","protected":false},"author":29,"featured_media":4182,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[217,3],"class_list":["post-4153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-clipboard","tag-javascript"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/pexels-photo-6991353.jpeg?fit=1880%2C1253&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=4153"}],"version-history":[{"count":7,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4153\/revisions"}],"predecessor-version":[{"id":4181,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4153\/revisions\/4181"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/4182"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=4153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=4153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=4153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}