Skip to content

Conversation

@DouglasDwyer
Copy link

This PR implements the ability to cut, copy, and paste text on the web/WASM platforms. This allows libraries like egui-winit to use the clipboard on the web (see emilk/egui#4270). This is accomplished in the following way:

  • Setting or clearing the clipboard is accomplished by calling window.navigator.clipboard.write()
  • Reading from the clipboard is accomplished by adding a paste event listener to the root HTML document, which stores the event.clipboardData.getData("text") value into a global variable. Whenever the clipboard contents are requested from Rust, the global variable is read. Note that this means the user must actually perform a paste before the clipboard contents become visible to Rust. This is a caveat, but it's the only way that I could find to implement synchronous pasting.
  • Image copying/pasting is not implemented. When images are pasted in a browser, they are returned in the event.clipboardData.files array, where async is required to read the data.

Copy link
Member

@complexspaces complexspaces left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR. I think the approach here makes sense for typical web applications. I'm not a web developer though 😅.

Question: Do you have the ability to test this in Safari? I know their Clipboard APIs are a bit different compared to Firefox and Chromium. I have the ability to test it myself but would need an example WASM app to run.

const GLOBAL_CLIPBOARD_OBJECT: &str = "__arboard_global_clipboard";

pub(crate) fn new() -> Result<Self, Error> {
let window = web_sys::window().ok_or(Error::ClipboardNotSupported)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Can this approach work in service workers/background workers? If not we can keep this hardcoded to window instead of global but that should be documented in the Clipboard documentation or similar.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately web workers cannot be supported - the clipboard API is not available in web workers (see the note on this page). I will add some documentation to mention this.

}

pub(crate) fn clear(self) -> Result<(), Error> {
let _ = self.clipboard.inner.write(&js_sys::Array::default());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the various clipboard calls failing return Error::Unknown?

Copy link
Author

@DouglasDwyer DouglasDwyer Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The calls with let _ = don't fail immediately; they return a Promise that resolves once the browser has updated the clipboard contents. Since this is a synchronous API, I just fire and forget the promise here.

The only instances in which these calls asynchronously fail (according to Mozilla docs) is if the page doesn't have permission to write to the user's clipboard. Clipboard permissions are granted with transient activation - that is, once the user interacts with the page, writing to the clipboard is allowed.

It would be nice if there was a way to report the error here. The fire and forget approach is a bit jank - but it does work for my use case, which is just handling normal copy/paste interactions with egui on the web.

@DouglasDwyer
Copy link
Author

I've gone ahead and attempted to address your feedback! The web has some security restrictions on what's possible, but this PR works perfectly for me with egui on the web, so I appreciate your review.

Question: Do you have the ability to test this in Safari? I know their Clipboard APIs are a bit different compared to Firefox and Chromium. I have the ability to test it myself but would need an example WASM app to run.

I sadly don't have access to a Mac right now. However, I've put together a really simple example web app for testing. You should be able to just clone the repository and run trunk serve to test it.

@complexspaces
Copy link
Member

Hi, just a quick update: I don't have the bandwidth at the moment to finish up the testing and reviewing for this PR. I apologize for the late communication but I'll need to circle back to it later, likely in October.

@complexspaces
Copy link
Member

Hello again, sorry for the radio silence. I ended up getting bogged down trying to figure out how to test this cross-platform and ensure consistent functionality.

#191 describes unblocking this being merged, so I would like to ask for slightly more time to set that up. My intent is that this would sit no longer then summer.

@complexspaces complexspaces added waiting on review The change is currently waiting on an arboard maintainer for a review or larger-scale update O-Web Work related to the web platform clipboard provided by JavaScript to WASM. enhancement New feature or request labels Jun 18, 2025
@DouglasDwyer
Copy link
Author

Thanks for your response! My own projects/needs have changed and I don't require this functionality right now. So, I'm happy to hear that this project is evolving but please take your time :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request O-Web Work related to the web platform clipboard provided by JavaScript to WASM. waiting on review The change is currently waiting on an arboard maintainer for a review or larger-scale update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants