# How to use the Synchronous Clipboard API without native code?

**URL:** <https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878>\
**Category:** Learn\
**Created:** [March 14, 2018, 9:23am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878 "2018-03-14T09:23:47Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![rexikan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rexikan/32/713_2.png) [@rexikan](https://discourse.elm-lang.org/u/rexikan)\
**Post date:** [March 14, 2018, 9:23am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/1 "2018-03-14T09:23:47Z")

</div>

I use the [Synchronous Clipboard API](https://www.w3.org/TR/clipboard-apis/#sync-clipboard-api) to implement copy/paste in my [Elm note-taking app](https://www.rexpad.com/). As the clipboardData only is available during the event, I rely on Native code to do side effects:

```
Html.div
    [ Html.Events.onWithOptions "copy"
        preventDefault
        (Decode.at ["clipboardData"] Decode.value
            |> Decode.map
                (\clipboard ->
                    let
                        _ =
                            Clipboard.setData "text/plain" selectionToText model clipboard

                        _ =
                            Clipboard.setData "text/x-rexpad-content" selectionContent model clipboard
                    in
                        NoAction
                )
        )
    , ...
    ]
    [...]

```

Where `Clipboard.setData` has the type `setData : String -> (a -> String) -> a -> Decode.Value -> Decode.Value` with this JavaScript implementation:

```
function setData(mimeType, transformer, model, clipboardData) {
  var data = transformer(model);
  if (data !== "") {
    clipboardData.setData(mimeType, data);
  }
  return clipboardData;
}

```

How could I do this without Native code on 0.18? Will 0.19 bring something that makes it possible?

---

<div class="post-metadata">

**Author:** ![mfeineis](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mfeineis/32/104_2.png) [@mfeineis](https://discourse.elm-lang.org/u/mfeineis)\
**Post date:** [March 14, 2018, 9:48am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/2 "2018-03-14T09:48:11Z")

</div>

What prevents you from using a port for this? You have the `clipboardData` `Value` at hand, why not just put that through an outgoing port and do the sideeffects there?

---

<div class="post-metadata">

**Author:** ![rexikan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rexikan/32/713_2.png) [@rexikan](https://discourse.elm-lang.org/u/rexikan)\
**Post date:** [March 14, 2018, 10:09am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/3 "2018-03-14T10:09:10Z")

</div>

The `clipboardData` value can not be used outside of the clipboard event. This is for privacy reasons I believe, preventing web pages to spy on the clipboard without the user knowing about it. During clipboard events, it is clear that the user intends to give access. Most things in Elm are asynchronous, but decoding happens synchronously.

---

<div class="post-metadata">

**Author:** ![mfeineis](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mfeineis/32/104_2.png) [@mfeineis](https://discourse.elm-lang.org/u/mfeineis)\
**Post date:** [March 14, 2018, 10:26am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/4 "2018-03-14T10:26:16Z")

</div>

Ah, I didn’t know about that privacy feature. Hmm, I only heard that user interaction handlers will be synchronous in 0.19, with an opt-in for async, so maybe the message will get forwarded to JavaScript via a port completely synchronous? I’m not sure, though. Interesting topic, I’m curious what the answer to this is.

---

<div class="post-metadata">

**Author:** ![hpate](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/hpate/32/2094_2.png) [@hpate](https://discourse.elm-lang.org/u/hpate)\
**Post date:** [March 14, 2018, 5:27pm UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/5 "2018-03-14T17:27:15Z")

</div>

We do this through delegated listeners, so we listen for `click` events on the body (in vanilla JS) that happen to have a `data-copy-clipboard` attribute that points to the stuff we want to copy, something like

```auto
<button data-copy-to-clipboard="#some-input"></button>

```

Then in the handler we run something like

```auto
  let elem = target && document.getElementById(target);
  if (elem) {
    elem.select();
    document.execCommand("copy");
  }

```

---

<div class="post-metadata">

**Author:** ![rexikan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rexikan/32/713_2.png) [@rexikan](https://discourse.elm-lang.org/u/rexikan)\
**Post date:** [March 14, 2018, 6:10pm UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/6 "2018-03-14T18:10:56Z")

</div>

Yes, this is a good click-to-copy-to-clipboard solution! I guess I could do something similar. I’m not sure about the performance though as I would have to prepare the to-be-copied text for several mime times in real time while drag-selecting the text.

---

<div class="post-metadata">

**Author:** ![luke](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/luke/32/709_2.png) [@luke](https://discourse.elm-lang.org/u/luke)\
**Post date:** [March 14, 2018, 6:14pm UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/7 "2018-03-14T18:14:34Z")

</div>

In 0.19 the scheduling of ports will change so that you can run functions that need to be in the same call stack as a user event handler. See: [Window.confirm without native code?](https://discourse.elm-lang.org/t/window-confirm-without-native-code/844/4?u=luke)

---

<div class="post-metadata">

**Author:** ![rexikan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rexikan/32/713_2.png) [@rexikan](https://discourse.elm-lang.org/u/rexikan)\
**Post date:** [March 14, 2018, 6:23pm UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/8 "2018-03-14T18:23:26Z")

</div>

Yes, I’m looking forward to 0.19 and synchronous event processing. And if that doesn’t do it, perhaps expanding on libs for the web APIs will.

---

<div class="post-metadata">

**Author:** ![luke](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/luke/32/709_2.png) [@luke](https://discourse.elm-lang.org/u/luke)\
**Post date:** [March 14, 2018, 6:25pm UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/9 "2018-03-14T18:25:53Z")

</div>

Forgive me! I missed your first question, how to do it in 0.18. I use a custom element:

> <https://github.com/lukewestby/ellie/blob/server-purs/client/src/Ellie/Ui/CopyText.elm#L13>

  

> <https://github.com/lukewestby/ellie/blob/server-purs/client/src/Ellie/Ui/CopyText.js>

---

<div class="post-metadata">

**Author:** ![rexikan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rexikan/32/713_2.png) [@rexikan](https://discourse.elm-lang.org/u/rexikan)\
**Post date:** [March 15, 2018, 9:00am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/10 "2018-03-15T09:00:05Z")

</div>

Thanks! I should look more into custom elements. In my case, I want to react on the clipboard events (`onpaste` and like) directly on the contenteditable (with content rendered in Elm).

---

<div class="post-metadata">

**Author:** ![luke](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/luke/32/709_2.png) [@luke](https://discourse.elm-lang.org/u/luke)\
**Post date:** [March 15, 2018, 11:17pm UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/11 "2018-03-15T23:17:16Z")

</div>

Right on! The one really important thing is that if you have a custom element with children that are rendered by Elm, you just can’t modify those children in a way that makes them different from what the virtual DOM thinks is true. As long as that rule is followed you can attach event listeners to whatever elements you want and do whatever you need to do.

---

<div class="post-metadata">

**Author:** ![Arthur\_Yuen](https://avatars.discourse-cdn.com/v4/letter/a/ce73a5/32.png) [@Arthur\_Yuen](https://discourse.elm-lang.org/u/Arthur_Yuen)\
**Post date:** [April 27, 2018, 10:18am UTC](https://discourse.elm-lang.org/t/how-to-use-the-synchronous-clipboard-api-without-native-code/878/12 "2018-04-27T10:18:43Z")

</div>

Hi @luke I want to ask do you need any special webpack to make this technique (copyedit elm + js) to work? I’m using create-elm-app and I couldn’t get the js file to load. Thanks.

update  
I’ve done more research on this and add [webcomponents polyfill](https://github.com/webcomponents/webcomponentsjs) and fixed this.  
Leave it here for any other people who came across this later.
