Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FF122 Clipboard API #31137

Merged
merged 32 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f37f4f3
FF122 Clipboard API - basic layout, style subedit, secure_context
hamishwillee Dec 19, 2023
69189e5
copy event clarification
hamishwillee Dec 19, 2023
70d4931
Remove Window: clipboardchange event from GroupData.json - not implem…
hamishwillee Dec 28, 2023
d0be555
Add Element cut/copy/paste events to overview
hamishwillee Dec 28, 2023
9e8432d
Security considerations
hamishwillee Dec 28, 2023
ab031ec
Events are 'of the Clipboard API'
hamishwillee Dec 28, 2023
4db8e13
Clipboard.write() requires transient activation
hamishwillee Dec 28, 2023
8ebdcb7
Clipboard.read() - update example and remove permissions
hamishwillee Dec 28, 2023
354dc46
Clipboard.read*/write* - remove permission mentions
hamishwillee Dec 29, 2023
0337079
Clipboard interface - remove permissions details
hamishwillee Dec 29, 2023
a257313
Clipboard API - make concepts a little less abstract
hamishwillee Dec 29, 2023
590fdf7
Navigator.clipboard - remove the text on requiring permissions
hamishwillee Dec 29, 2023
5b41930
Minor tweaks
hamishwillee Dec 29, 2023
6fdedb8
Permissions API- remove clipboard permissions
hamishwillee Jan 4, 2024
337163b
Add note about Chromium behaviour
hamishwillee Jan 4, 2024
19e4579
read() example handles the permissions handled/or not handled
hamishwillee Jan 5, 2024
0009e9b
Merge specific suggestions from code review
hamishwillee Jan 8, 2024
cf84e02
Fix example as per feedback
hamishwillee Jan 8, 2024
230076a
read - add example for more reading of data
hamishwillee Jan 8, 2024
b8de2c3
Remove guide on interacting with web extensions
hamishwillee Jan 8, 2024
5916b79
Security requirements
hamishwillee Jan 8, 2024
3c6f1f9
Add security considerations to the other methods
hamishwillee Jan 8, 2024
274e7e6
Fix typos. Update readText
hamishwillee Jan 8, 2024
310dfc1
Make examples async
hamishwillee Jan 8, 2024
d66a63d
Remove that write one at a time comment
hamishwillee Jan 8, 2024
a4767ae
Update files/en-us/web/api/clipboard_api/index.md
wbamberg Jan 8, 2024
c8adb13
typo
wbamberg Jan 8, 2024
77e96f5
Apply suggestions from code review
hamishwillee Jan 8, 2024
304937c
Update files/en-us/web/api/clipboard/read/index.md
hamishwillee Jan 8, 2024
e0d3b01
Test image source has effect on rendering
hamishwillee Jan 8, 2024
7476556
Remove clock (not rendering). Try sample link for chromium
hamishwillee Jan 9, 2024
657a168
Remove the live sample link
hamishwillee Jan 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions files/en-us/web/api/clipboard/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ browser-compat: api.Clipboard

{{APIRef("Clipboard API")}}{{SecureContext_Header}}

The **`Clipboard`** interface implements the [Clipboard API](/en-US/docs/Web/API/Clipboard_API), providing—if the user grants permission—both read and write access to the contents of the system clipboard. The Clipboard API can be used to implement cut, copy, and paste features within a web application.
The **`Clipboard`** interface of the [Clipboard API](/en-US/docs/Web/API/Clipboard_API) provides read and write access to the contents of the system clipboard.
This allows a web application to implement cut, copy, and paste features.

{{InheritanceDiagram}}

The system clipboard is exposed through the global {{domxref("Navigator.clipboard")}} property.

Calls to the methods of the `Clipboard` object will not succeed if the user hasn't granted the needed permissions using the [Permissions API](/en-US/docs/Web/API/Permissions_API) and the `'clipboard-read'` or `'clipboard-write'` permission as appropriate.
All of the Clipboard API methods operate asynchronously; they return a {{jsxref("Promise")}} which is resolved once the clipboard access has been completed.
The promise is rejected if clipboard access is denied.

> **Note:** In reality, at this time browser requirements for access to the clipboard vary significantly. Please see the section [Clipboard availability](#clipboard_availability) for details.

All of the Clipboard API methods operate asynchronously; they return a {{jsxref("Promise")}} which is resolved once the clipboard access has been completed. The promise is rejected if clipboard access is denied.
All the methods require a [secure context](/en-US/docs/Web/Security/Secure_Contexts).
Additional requirements for using the API are discussed in the [Security consideration](/en-US/docs/Web/API/Clipboard_API#security_considerations) section of the API overview topic.

## Instance methods

Expand All @@ -26,17 +27,11 @@ _`Clipboard` is based on the {{domxref("EventTarget")}} interface, and includes
- {{domxref("Clipboard.read()","read()")}}
- : Requests arbitrary data (such as images) from the clipboard, returning a {{jsxref("Promise")}} that resolves with an array of {{domxref("ClipboardItem")}} objects containing the clipboard's contents.
- {{domxref("Clipboard.readText()","readText()")}}
- : Requests text from the system clipboard; returns a `Promise` which is resolved with a string containing the clipboard's text once it's available.
- : Requests text from the system clipboard, returning a {{jsxref("Promise")}} that is fulfilled with a string containing the clipboard's text once it's available.
- {{domxref("Clipboard.write()","write()")}}
- : Writes arbitrary data to the system clipboard. This asynchronous operation signals that it's finished by resolving the returned `Promise`.
- : Writes arbitrary data to the system clipboard, returning a {{jsxref("Promise")}} that resolves when the operation completes.
- {{domxref("Clipboard.writeText()","writeText()")}}
- : Writes text to the system clipboard, returning a `Promise` which is resolved once the text is fully copied into the clipboard.

## Clipboard availability

The asynchronous clipboard API is a relatively recent addition, and the process of implementing it in browsers is not yet complete. Due to both potential security concerns and technical complexities, the process of integrating this API is happening gradually in most browsers. See the [browser compatibility](#browser_compatibility) section below for more information.

In browser extensions, you can access the system clipboard using the WebExtension [`clipboard`](/en-US/docs/Mozilla/Add-ons/WebExtensions/API/clipboard) API.
- : Writes text to the system clipboard, returning a {{jsxref("Promise")}} that is resolved once the text is fully copied into the clipboard.

## Specifications

Expand Down
208 changes: 172 additions & 36 deletions files/en-us/web/api/clipboard/read/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ page-type: web-api-instance-method
browser-compat: api.Clipboard.read
---

{{APIRef("Clipboard API")}}
{{APIRef("Clipboard API")}} {{securecontext_header}}

The **`read()`** method of the
{{domxref("Clipboard")}} interface requests a copy of the clipboard's contents,
delivering the data to the returned {{jsxref("Promise")}} when the promise is
resolved. Unlike {{domxref("Clipboard.readText", "readText()")}}, the
`read()` method can return arbitrary data, such as images. This method can
also return text.
The **`read()`** method of the {{domxref("Clipboard")}} interface requests a copy of the clipboard's contents, fulfilling the returned {{jsxref("Promise")}} with the data.

> **Note:** The asynchronous Clipboard and [Permissions APIs](/en-US/docs/Web/API/Permissions_API) are still in the
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
> process of being integrated into most browsers, so they often deviate from the
> official rules for permissions and the like. Be sure to review the [compatibility table](#browser_compatibility) before using these methods.
The method can in theory return arbitrary data (unlike {{domxref("Clipboard.readText", "readText()")}}, which can only return text).
Browsers commonly support reading text, HTML, and PNG image data — see [browser compatibility](#browser_compatibility) for more information.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

## Syntax
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -31,37 +25,32 @@ None.

### Return value

A {{jsxref("Promise")}} that resolves with an array of {{domxref("ClipboardItem")}} objects
containing the clipboard's contents. The promise is rejected if permission to access the
clipboard is not granted.
A {{jsxref("Promise")}} that resolves with an array of {{domxref("ClipboardItem")}} objects containing the clipboard's contents.

## Security
### Exceptions

[Transient user activation](/en-US/docs/Web/Security/User_activation) is required. The user has to interact with the page or a UI element in order for this feature to work.
- `NotAllowedError` {{domxref("DOMException")}}
- : Thrown if the reading from the clipboard is not allowed.

To read from the clipboard, you must first have the `"clipboard-read"`
permission.
## Security considerations

## Examples

### Reading image data
Reading from the clipboard can only be done in a [secure context](/en-US/docs/Web/Security/Secure_Contexts).

This example uses the `read()` method to read image data from the clipboard.
Additional security requirements are covered in the [Security consideration](/en-US/docs/Web/API/Clipboard_API#security_considerations) section of the API overview topic.

Try copying the butterfly image on the left using the "Copy image" context menu item, then click in the empty frame on the right.
## Examples

The example will check or ask for permission to read the clipboard, then fetch the image data and display the image data in the empty frame.
### Reading image data from clipboard

> **Note:** At this time, while Firefox does implement
> `read()`, it does not recognize the `"clipboard-read"`
> permission, so attempting to use the [Permissions API](/en-US/docs/Web/API/Permissions_API) to manage access to
> the API will not work.
This example uses the `read()` method to read image data from the clipboard and paste it into an {{HTMLElement("img")}} element.

#### HTML

```html
<img id="source" src="butterfly.jpg" alt="A butterfly" />
<img id="destination" />
<button id="reload" type="button">Reload</button>
<p id="log"></p>
```

#### CSS
Expand All @@ -73,39 +62,183 @@ img {
margin: 0 1rem;
border: 1px solid black;
}
#reload {
display: block;
margin: 0 1rem;
}
```

#### JavaScript

This code provides a mechanism to log any errors to the element with id `log`.

```js
const logElement = document.querySelector("#log");
function log(text) {
logElement.innerText = `Error: ${text}`;
}
```

We also add code to reload and clear the example when the "Reload" button is pressed.

```js
const reload = document.querySelector("#reload");

reload.addEventListener("click", () => {
window.location.reload(true);
});
```

The remaining code reads the clipboard when the destination element is clicked and copies the image data into the `destinationImage` element.
It logs an error if it is unable to use the `read()` method, or if the clipboard does not contain data in PNG format.

```js
const destinationImage = document.querySelector("#destination");
destinationImage.addEventListener("click", pasteImage);

async function pasteImage() {
try {
const permission = await navigator.permissions.query({
name: "clipboard-read",
});
if (permission.state === "denied") {
throw new Error("Not allowed to read clipboard.");
}
const clipboardContents = await navigator.clipboard.read();
for (const item of clipboardContents) {
if (!item.types.includes("image/png")) {
throw new Error("Clipboard contains non-image data.");
throw new Error("Clipboard does not contain PNG image data.");
}
const blob = await item.getType("image/png");
destinationImage.src = URL.createObjectURL(blob);
}
} catch (error) {
console.error(error.message);
log(error.message);
}
}
```

#### Result

Copy the butterfly image on the left by right-clicking the image and selecting "Copy image" from the context menu.
Then click on the empty frame on the right.
The example will fetch the image data from the clipboard and display the image in the empty frame.

{{EmbedLiveSample("Reading image data from clipboard", "100%", "200")}}

> **Note:** If prompted, grant permission in order to paste the image.

### Reading data from the clipboard

This example uses the `read()` method to read data from the clipboard and log whatever data is stored in the clipboard.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

This differs from the previous version in that it will display text, HTML, and image {{domxref("ClipboardItem")}} objects (rather than just images).

#### HTML

```html
<img id="source_jpg" src="butterfly.jpg" alt="JPG butterfly image" />
<div id="destination">Click here to copy clipboard data.</div>
<button id="reload" type="button">Reload</button>
<p id="log"></p>
```

#### CSS

```css
img {
height: 100px;
width: 100px;
margin: 0 1rem;
border: 1px solid black;
}

#destination {
min-height: 300px;
min-width: 90%;
margin: 0 1rem;
border: 1px solid black;
}

#reload {
display: block;
margin: 0 1rem;
}
```

#### JavaScript

This code provides a mechanism to log any errors to the element with id `log`.

```js
const logElement = document.querySelector("#log");
function log(text) {
logElement.innerText = `Error: ${text}`;
}
```

We also add code to reload and clear the example when the "Reload" button is pressed.

```js
const reload = document.querySelector("#reload");

reload.addEventListener("click", () => {
window.location.reload(true);
});
```

The remaining code reads the clipboard when the destination element is clicked and displays each {{domxref("ClipboardItem")}} element along with its MIME type.
It logs an error it is unable to use the `read()` method, or if the clipboard contains any other MIME type.

```js
const destinationDiv = document.querySelector("#destination");
destinationDiv.addEventListener("click", pasteData);

async function pasteData() {
destinationDiv.innerText = ""; //Clear inner text
try {
const clipboardContents = await navigator.clipboard.read();
for (const item of clipboardContents) {
for (const mimeType of item.types) {
const mimeTypeElement = document.createElement("p");
mimeTypeElement.innerText = `MIME type: ${mimeType}`;
destinationDiv.appendChild(mimeTypeElement);
if (mimeType === "image/png") {
const pngImage = new Image(); // Image constructor
pngImage.src = "image1.png";
pngImage.alt = "PNG image from clipboard";
const blob = await item.getType("image/png");
pngImage.src = URL.createObjectURL(blob);
destinationDiv.appendChild(pngImage);
} else if (mimeType === "text/html") {
const blob = await item.getType("text/html");
const blobText = await blob.text();
const clipHTML = document.createElement("pre");
clipHTML.innerText = blobText;
destinationDiv.appendChild(clipHTML);
} else if (mimeType === "text/plain") {
const blob = await item.getType("text/plain");
const blobText = await blob.text();
const clipPlain = document.createElement("pre");
clipPlain.innerText = blobText;
destinationDiv.appendChild(clipPlain);
} else {
throw new Error(`${mimeType} not supported.`);
}
}
}
} catch (error) {
log(error.message);
}
}
```

#### Result

{{EmbedLiveSample("Reading image data")}}
Copy some text or the butterfly (JPG) image below (to copy images right-click on them and then select "Copy image" from the context menu).
Select the indicated frame below to paste this information from the clipboard into the frame.

{{EmbedLiveSample("Reading data from the clipboard", "100%", "450")}}

Notes:

- Even though the butterfly image is a JPG file, when read from the clipboard it is a PNG.
- If prompted, you will need to grant permission in order to paste the image.
- This may not work on chromium browsers as the sample frame is not granted the [Permissions-Policy](/en-US/docs/Web/HTTP/Headers/Permissions-Policy) `clipboard-read` and `clipboard-write` permissions ([required by Chromium browsers](/en-US/docs/Web/API/Clipboard_API#security_considerations)).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@wbamberg As discussed, I couldn't get the second image to display - created an issue in mdn/yari#10287

This also logs an error on Chromium due to the permissions policy not being granted to the live sample frame. I tried a LiveSampleLink because I figured that might work, but on PR preview that page gives a "Not found".

Anyway, think this is good for a re-review.


## Specifications

Expand All @@ -119,3 +252,6 @@ async function pasteImage() {

- [Clipboard API](/en-US/docs/Web/API/Clipboard_API)
- [Image support for Async Clipboard article](https://web.dev/articles/async-clipboard)
- {{domxref("Clipboard.readText()")}}
- {{domxref("Clipboard.writeText()")}}
- {{domxref("Clipboard.write()")}}
44 changes: 25 additions & 19 deletions files/en-us/web/api/clipboard/readtext/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ page-type: web-api-instance-method
browser-compat: api.Clipboard.readText
---

{{APIRef("Clipboard API")}}
{{APIRef("Clipboard API")}} {{securecontext_header}}

The **{{domxref("Clipboard")}}** interface's
**`readText()`** method returns a {{jsxref("Promise")}} which
resolves with a copy of the textual contents of the system clipboard.
The **`readText()`** method of the {{domxref("Clipboard")}} interface returns a {{jsxref("Promise")}} which fulfils with a copy of the textual contents of the system clipboard.

> **Note:** To read non-text contents from the clipboard, use the {{domxref("Clipboard.read", "read()")}} method instead.
> You can write text to the clipboard using {{domxref("Clipboard.writeText", "writeText()")}}.

## Syntax

Expand All @@ -24,30 +25,34 @@ None.

### Return value

A {{jsxref("Promise")}} that resolves with a string containing the
textual contents of the clipboard. Returns an empty string if the clipboard is empty,
does not contain text, or does not include a textual representation among the
{{domxref("DataTransfer")}} objects representing the clipboard's contents.
A {{jsxref("Promise")}} that resolves with a string containing the textual contents of the clipboard.

Returns an empty string if the clipboard is empty, does not contain text, or does not include a textual representation among the objects representing the clipboard's contents.

### Exceptions

To read non-text contents from the clipboard, use the {{domxref("Clipboard.read",
"read()")}} method instead. You can write text to the clipboard using
{{domxref("Clipboard.writeText", "writeText()")}}.
- `NotAllowedError` {{domxref("DOMException")}}
- : Thrown if the access to read the clipboard is not allowed.
- `NotFoundError` {{domxref("DOMException")}}
- : Thrown if the clipboard indicates that it contains data that can be represented as a text but is unable to provide a textual representation.

## Security
## Security considerations

[Transient user activation](/en-US/docs/Web/Security/User_activation) is required. The user has to interact with the page or a UI element in order for this feature to work.
Reading from the clipboard can only be done in a [secure context](/en-US/docs/Web/Security/Secure_Contexts).

The `"clipboard-read"` permission of the [Permissions API](/en-US/docs/Web/API/Permissions_API) must be granted before you can read data from the clipboard.
Additional security requirements are covered in the [Security consideration](/en-US/docs/Web/API/Clipboard_API#security_considerations) section of the API overview topic.

## Examples

This example retrieves the textual contents of the clipboard and inserts the returned
text into an element's contents.
This example retrieves the textual contents of the clipboard and inserts the returned text into a selected element's contents.

```js
navigator.clipboard
.readText()
.then((clipText) => (document.getElementById("outbox").innerText = clipText));
const destination = document.getElementById("outbox");
destinationImage.addEventListener("click", () => {
navigator.clipboard
.readText()
.then((clipText) => (destination.innerText = clipText));
});
```

## Specifications
Expand All @@ -62,5 +67,6 @@ navigator.clipboard

- [Clipboard API](/en-US/docs/Web/API/Clipboard_API)
- [Image support for Async Clipboard article](https://web.dev/articles/async-clipboard)
- {{domxref("Clipboard.read()")}}
- {{domxref("Clipboard.writeText()")}}
- {{domxref("Clipboard.write()")}}
Loading